Skip to content

Commit

Permalink
ongoing work on JsonEscapeUtil
Browse files Browse the repository at this point in the history
Signed-off-by: Ceki Gulcu <ceki@qos.ch>
  • Loading branch information
ceki committed May 1, 2023
1 parent b8e0936 commit 22da156
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 146 deletions.
Original file line number Diff line number Diff line change
@@ -1,140 +1,2 @@
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();
}
package ch.qos.logback.classic.encoder;public class JsonEncoder {
}
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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,8 @@

import static org.junit.jupiter.api.Assertions.assertEquals;



@Disabled
public class JsonEncoderTest {



LoggerContext context = new LoggerContext();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Logger logger = context.getLogger(PatternLayoutEncoderTest.class);
Expand All @@ -54,7 +49,32 @@ public void smoke() throws IOException {
ILoggingEvent event = makeLoggingEvent(msg);
byte[] eventBytes = je.encode(event);
baos.write(eventBytes);
assertEquals(msg, baos.toString());
String witnessPattern = makeWitness(event);
assertEquals(witnessPattern, baos.toString());
}

@Test
public void twoEvents() throws IOException {

ILoggingEvent event0 = makeLoggingEvent("hello");
ILoggingEvent event1 = makeLoggingEvent("world");

byte[] eventBytes0 = je.encode(event0);
byte[] eventBytes1 = je.encode(event1);

baos.write(eventBytes0);
baos.write(eventBytes1);

String witnessPattern0 = makeWitness(event0);
String witnessPattern1 = makeWitness(event1);

assertEquals(witnessPattern0+witnessPattern1, baos.toString());
}


private static String makeWitness(ILoggingEvent event) {
return "{\"level\":\"" + event.getLevel() + "\",\"message\":\"" + event.getMessage() + "\",\"thread\":\""
+ event.getThreadName() + "\",\"logger\":\"" + event.getLoggerName() + "\"}";
}

ILoggingEvent makeLoggingEvent(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
*/
package ch.qos.logback.core;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class CoreConstants {

final public static String DISABLE_SERVLET_CONTAINER_INITIALIZER_KEY = "logbackDisableServletContainerInitializer";
Expand Down Expand Up @@ -107,6 +110,8 @@ public class CoreConstants {
*/
public static final String[] EMPTY_STRING_ARRAY = new String[] {};

public static final Charset UTF_8_CHARSET = StandardCharsets.UTF_8;

/**
* An empty Class array.
*/
Expand All @@ -129,6 +134,7 @@ public class CoreConstants {
public static final char DASH_CHAR = '-';
public static final String DEFAULT_VALUE_SEPARATOR = ":-";

public static final String NULL_STR = "null";
/**
* Number of rows before in an HTML table before, we close the table and create
* a new one
Expand Down

0 comments on commit 22da156

Please sign in to comment.