-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Ceki Gulcu <[email protected]>
- Loading branch information
Showing
6 changed files
with
302 additions
and
1 deletion.
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
logback-classic/src/main/java/ch/qos/logback/classic/encoder/JsonEncoder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
package ch.qos.logback.classic.encoder;public class JsonEncoder { | ||
} |
140 changes: 140 additions & 0 deletions
140
logback-classic/src/main/java/ch/qos/logback/classic/encoder/JsonEncoder2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package ch.qos.logback.classic.encoder; | ||
|
||
import ch.qos.logback.classic.spi.ILoggingEvent; | ||
import ch.qos.logback.core.encoder.JsonEncoderBase; | ||
import ch.qos.logback.core.util.DirectJson; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* This is a concrete JsonEncoder for {@link ILoggingEvent} that emits fields according to object's configuration. | ||
* It is partially imported from <a href="https://github.com/hkupty/penna">penna</a>, but adapted to logback's structure. | ||
* | ||
* @author Henry John Kupty | ||
*/ | ||
public class JsonEncoder extends JsonEncoderBase<ILoggingEvent> { | ||
|
||
|
||
// Excerpt below imported from | ||
// ch.qos.logback.contrib.json.classic.JsonLayout | ||
public static final String TIMESTAMP_ATTR_NAME = "timestamp"; | ||
public static final String LEVEL_ATTR_NAME = "level"; | ||
public static final String MARKERS_ATTR_NAME = "tags"; | ||
public static final String THREAD_ATTR_NAME = "thread"; | ||
public static final String MDC_ATTR_NAME = "mdc"; | ||
public static final String LOGGER_ATTR_NAME = "logger"; | ||
public static final String FORMATTED_MESSAGE_ATTR_NAME = "message"; | ||
public static final String MESSAGE_ATTR_NAME = "raw-message"; | ||
public static final String EXCEPTION_ATTR_NAME = "exception"; | ||
public static final String CONTEXT_ATTR_NAME = "context"; | ||
|
||
protected boolean includeLevel; | ||
protected boolean includeThreadName; | ||
protected boolean includeMDC; | ||
protected boolean includeLoggerName; | ||
protected boolean includeFormattedMessage; | ||
protected boolean includeMessage; | ||
protected boolean includeException; | ||
protected boolean includeContextName; | ||
|
||
private final List<Emitter<ILoggingEvent>> emitters; | ||
|
||
|
||
public JsonEncoder() { | ||
super(); | ||
|
||
emitters = new ArrayList<>(); | ||
this.includeLevel = true; | ||
this.includeThreadName = true; | ||
this.includeMDC = true; | ||
this.includeLoggerName = true; | ||
this.includeFormattedMessage = true; | ||
this.includeException = true; | ||
this.includeContextName = true; | ||
} | ||
|
||
//protected = new DirectJson(); | ||
|
||
|
||
public void writeMessage(DirectJson jsonWriter, ILoggingEvent event) { | ||
jsonWriter.writeStringValue(MESSAGE_ATTR_NAME, event.getMessage()); | ||
} | ||
|
||
public void writeFormattedMessage(DirectJson jsonWriter, ILoggingEvent event) { | ||
jsonWriter.writeStringValue(FORMATTED_MESSAGE_ATTR_NAME, event.getFormattedMessage()); | ||
} | ||
|
||
public void writeLogger(DirectJson jsonWriter, ILoggingEvent event) { | ||
jsonWriter.writeStringValue(LOGGER_ATTR_NAME, event.getLoggerName()); | ||
} | ||
|
||
public void writeThreadName(DirectJson jsonWriter, ILoggingEvent event) { | ||
jsonWriter.writeStringValue(THREAD_ATTR_NAME, event.getThreadName()); | ||
} | ||
|
||
public void writeLevel(DirectJson jsonWriter, ILoggingEvent event) { | ||
jsonWriter.writeStringValue(LEVEL_ATTR_NAME, event.getLevel().levelStr); | ||
} | ||
|
||
|
||
public void writeMarkers(DirectJson jsonWriter, ILoggingEvent event) { | ||
var markers = event.getMarkerList(); | ||
if (!markers.isEmpty()) { | ||
jsonWriter.openArray(MARKERS_ATTR_NAME); | ||
for (var marker : markers) { | ||
jsonWriter.writeString(marker.getName()); | ||
jsonWriter.writeSep(); | ||
} | ||
// Close array will overwrite the last "," in the buffer, so we are OK | ||
jsonWriter.closeArray(); | ||
jsonWriter.writeSep(); | ||
} | ||
} | ||
|
||
public void writeMdc(DirectJson jsonWriter, ILoggingEvent event) { | ||
var mdc = event.getMDCPropertyMap(); | ||
if (!mdc.isEmpty()) { | ||
jsonWriter.openObject(MDC_ATTR_NAME); | ||
for (var entry : mdc.entrySet()) { | ||
jsonWriter.writeStringValue(entry.getKey(), entry.getValue()); | ||
} | ||
jsonWriter.closeObject(); | ||
jsonWriter.writeSep(); | ||
} | ||
} | ||
|
||
private void buildEmitterList() { | ||
// This method should be re-entrant and allow for reconfiguring the emitters if something change; | ||
emitters.clear(); | ||
|
||
// TODO figure out order | ||
if (includeLevel) emitters.add(this::writeLevel); | ||
if (includeMDC) emitters.add(this::writeMdc); | ||
if (includeMessage) emitters.add(this::writeMessage); | ||
if (includeFormattedMessage) emitters.add(this::writeFormattedMessage); | ||
if (includeThreadName) emitters.add(this::writeThreadName); | ||
if (includeLoggerName) emitters.add(this::writeLogger); | ||
// TODO add fields missing: | ||
// context | ||
// exception | ||
// custom data | ||
// marker | ||
} | ||
|
||
@Override | ||
public byte[] encode(ILoggingEvent event) { | ||
if (emitters.isEmpty()) { | ||
buildEmitterList(); | ||
} | ||
DirectJson jsonWriter = new DirectJson(); | ||
jsonWriter.openObject(); | ||
|
||
for (var emitter: emitters) { | ||
emitter.write(jsonWriter, event); | ||
} | ||
|
||
jsonWriter.closeObject(); | ||
return jsonWriter.flush(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
logback-core/src/main/java/ch/qos/logback/core/encoder/JsonEscapeUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Logback: the reliable, generic, fast and flexible logging framework. | ||
* Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
* | ||
* This program and the accompanying materials are dual-licensed under | ||
* either the terms of the Eclipse Public License v1.0 as published by | ||
* the Eclipse Foundation | ||
* | ||
* or (per the licensee's choosing) | ||
* | ||
* under the terms of the GNU Lesser General Public License version 2.1 | ||
* as published by the Free Software Foundation. | ||
*/ | ||
|
||
package ch.qos.logback.core.encoder; | ||
|
||
public class JsonEscapeUtil { | ||
|
||
protected final static char[] HEXADECIMALS_TABLE = "0123456789ABCDEF".toCharArray(); | ||
|
||
|
||
static final int ESCAPE_CODES_COUNT = 32; | ||
|
||
static final String[] ESCAPE_CODES = new String[ESCAPE_CODES_COUNT]; | ||
|
||
|
||
// From RFC-8259 page 5 | ||
|
||
// %x22 / ; " quotation mark U+0022 | ||
// %x5C / ; \ reverse solidus U+005C | ||
// %x2F / ; / solidus U+002F | ||
|
||
// %x62 / ; b backspace U+0008 | ||
// %x74 / ; t tab U+0009 | ||
// %x6E / ; n line feed U+000A | ||
// %x66 / ; f form feed U+000C | ||
// %x72 / ; r carriage return U+000D | ||
|
||
static { | ||
for(char c = 0; c < ESCAPE_CODES_COUNT; c++) { | ||
|
||
switch(c) { | ||
case 0x08: ESCAPE_CODES[c] = "\\b"; | ||
break; | ||
case 0x09: ESCAPE_CODES[c] = "\\t"; | ||
break; | ||
case 0x0A: ESCAPE_CODES[c] = "\\n"; | ||
break; | ||
case 0x0C: ESCAPE_CODES[c] = "\\f"; | ||
break; | ||
case 0x0D: ESCAPE_CODES[c] = "\\r"; | ||
break; | ||
default: | ||
ESCAPE_CODES[c] = getEscapeCodeBelowASCII32(c); | ||
} | ||
} | ||
} | ||
static String getEscapeCodeBelowASCII32(char c) { | ||
if(c > 32) { | ||
throw new IllegalArgumentException("input must be less than 32"); | ||
} | ||
|
||
StringBuilder sb = new StringBuilder(6); | ||
sb.append("\\u00"); | ||
|
||
int highPart = c >> 4; | ||
sb.append(HEXADECIMALS_TABLE[highPart]); | ||
|
||
int lowPart = c & 0x0F; | ||
sb.append(HEXADECIMALS_TABLE[lowPart]); | ||
|
||
|
||
return sb.toString(); | ||
} | ||
|
||
// %x22 / ; " quotation mark U+0022 | ||
// %x5C / ; \ reverse solidus U+005C | ||
|
||
static String getObligatoryEscapeCode(char c) { | ||
if(c < 32) | ||
return getEscapeCodeBelowASCII32(c); | ||
if(c == 0x22) | ||
return "\\\""; | ||
if(c == 0x5C) | ||
return "\\/"; | ||
|
||
return null; | ||
} | ||
|
||
static String jsonEscapeString(String input) { | ||
int length = input.length(); | ||
int lenthWithLeeway = (int) (length*1.1); | ||
|
||
StringBuilder sb = new StringBuilder(lenthWithLeeway); | ||
for(int i = 0; i < length; i++) { | ||
final char c = input.charAt(i); | ||
String escaped = getObligatoryEscapeCode(c); | ||
if(escaped == null) | ||
sb.append(c); | ||
else | ||
sb.append(escaped); | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
logback-core/src/test/java/ch/qos/logback/core/encoder/JsonEscapeUtilTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* Logback: the reliable, generic, fast and flexible logging framework. | ||
* Copyright (C) 1999-2023, QOS.ch. All rights reserved. | ||
* | ||
* This program and the accompanying materials are dual-licensed under | ||
* either the terms of the Eclipse Public License v1.0 as published by | ||
* the Eclipse Foundation | ||
* | ||
* or (per the licensee's choosing) | ||
* | ||
* under the terms of the GNU Lesser General Public License version 2.1 | ||
* as published by the Free Software Foundation. | ||
*/ | ||
|
||
package ch.qos.logback.core.encoder; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
class JsonEscapeUtilTest { | ||
|
||
@Test | ||
public void testEscapeCodes() { | ||
assertEquals("\\u0001", JsonEscapeUtil.ESCAPE_CODES[1]); | ||
assertEquals("\\u0005", JsonEscapeUtil.ESCAPE_CODES[5]); | ||
assertEquals("\\b", JsonEscapeUtil.ESCAPE_CODES[8]); | ||
assertEquals("\\t", JsonEscapeUtil.ESCAPE_CODES[9]); | ||
assertEquals("\\n", JsonEscapeUtil.ESCAPE_CODES[0x0A]); | ||
assertEquals("\\u000B", JsonEscapeUtil.ESCAPE_CODES[0x0B]); | ||
assertEquals("\\f", JsonEscapeUtil.ESCAPE_CODES[0x0C]); | ||
assertEquals("\\r", JsonEscapeUtil.ESCAPE_CODES[0x0D]); | ||
assertEquals("\\u000E", JsonEscapeUtil.ESCAPE_CODES[0x0E]); | ||
|
||
assertEquals("\\u001A", JsonEscapeUtil.ESCAPE_CODES[0x1A]); | ||
} | ||
|
||
@Test | ||
public void testEscapeString() { | ||
assertEquals("abc", JsonEscapeUtil.jsonEscapeString("abc")); | ||
assertEquals("{world: \\\"world\\\"}", JsonEscapeUtil.jsonEscapeString("{world: \"world\"}")); | ||
assertEquals("{world: "+'\\'+'"'+"world\\\"}", JsonEscapeUtil.jsonEscapeString("{world: \"world\"}")); | ||
} | ||
} |