Skip to content

Commit

Permalink
Issue #17: Numeric Properties
Browse files Browse the repository at this point in the history
  • Loading branch information
merchanjavier committed Oct 12, 2017
1 parent 3b4a726 commit 6024368
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -116,6 +116,7 @@ The fields `@timestamp` and `message` are always sent and can not currently be c
* `name` (required): Key to be used in the log event
* `value` (required): Text string to be sent. Internally, the value is populated using a Logback PatternLayout, so all [Conversion Words](http://logback.qos.ch/manual/layouts.html#conversionWord) can be used (in addition to the standard static variable interpolations like `${HOSTNAME}`).
* `allowEmpty` (optional, default `false`): Normally, if the `value` results in a `null` or empty string, the field will not be sent. If `allowEmpty` is set to `true` then the field will be sent regardless
* `type` (optional, default `String`): type of the field on the resulting JSON message. Possible values are: `String`, `int`, `float` and `boolean`.

Groovy Configuration
====================
Expand Down
Expand Up @@ -49,6 +49,7 @@ protected DateFormat initialValue() {

private volatile boolean working;

private final PropertySerializer propertySerializer = PropertySerializer.getInstance();

public AbstractElasticsearchPublisher(Context context, ErrorReporter errorReporter, Settings settings, ElasticsearchProperties properties, HttpRequestHeaders headers) throws IOException {
this.errorReporter = errorReporter;
Expand Down Expand Up @@ -169,13 +170,13 @@ private void serializeEvents(JsonGenerator gen, List<T> eventsCopy, List<Abstrac

private void serializeIndexString(JsonGenerator gen, T event) throws IOException {
gen.writeStartObject();
gen.writeObjectFieldStart("index");
gen.writeObjectField("_index", indexPattern.encode(event));
String type = settings.getType();
if (type != null) {
gen.writeObjectField("_type", type);
}
gen.writeEndObject();
gen.writeObjectFieldStart("index");
gen.writeObjectField("_index", indexPattern.encode(event));
String type = settings.getType();
if (type != null) {
gen.writeObjectField("_type", type);
}
gen.writeEndObject();
gen.writeEndObject();
}

Expand All @@ -185,10 +186,7 @@ private void serializeEvent(JsonGenerator gen, T event, List<AbstractPropertyAnd
serializeCommonFields(gen, event);

for (AbstractPropertyAndEncoder<T> pae : propertyList) {
String value = pae.encode(event);
if (pae.allowEmpty() || (value != null && !value.isEmpty())) {
gen.writeObjectField(pae.getName(), value);
}
propertySerializer.serializeProperty(gen, event, pae);
}

gen.writeEndObject();
Expand Down
@@ -0,0 +1,67 @@
package com.internetitem.logback.elasticsearch;

import com.fasterxml.jackson.core.JsonGenerator;
import com.internetitem.logback.elasticsearch.util.AbstractPropertyAndEncoder;

import java.io.IOException;

class PropertySerializer<T> {
private PropertySerializer() {
}

private static PropertySerializer INSTANCE = null;

static synchronized PropertySerializer getInstance() {
if (INSTANCE == null) {
INSTANCE = new PropertySerializer();
}
return INSTANCE;
}

synchronized void serializeProperty(JsonGenerator jsonGenerator, T event, AbstractPropertyAndEncoder<T> propertyAndEncoder) throws IOException {
String value = propertyAndEncoder.encode(event);
if (propertyAndEncoder.allowEmpty() || (value != null && !value.isEmpty())) {
switch (propertyAndEncoder.getType()) {
case INT:
serializeIntField(jsonGenerator, propertyAndEncoder, value);
break;
case FLOAT:
serializeFloatField(jsonGenerator, propertyAndEncoder, value);
break;
case BOOLEAN:
serializeBooleanField(jsonGenerator, propertyAndEncoder, value);
break;
default:
serializeStringField(jsonGenerator, propertyAndEncoder, value);
}
}
}

private void serializeStringField(JsonGenerator jsonGenerator, AbstractPropertyAndEncoder<T> propertyAndEncoder, String value) throws IOException {
jsonGenerator.writeObjectField(propertyAndEncoder.getName(), value);
}

private void serializeIntField(JsonGenerator jsonGenerator, AbstractPropertyAndEncoder<T> propertyAndEncoder, String value) throws IOException {
try {
jsonGenerator.writeNumberField(propertyAndEncoder.getName(), Integer.valueOf(value));
} catch (NumberFormatException e) {
serializeStringField(jsonGenerator, propertyAndEncoder, value);
}
}

private void serializeFloatField(JsonGenerator jsonGenerator, AbstractPropertyAndEncoder<T> propertyAndEncoder, String value) throws IOException {
try {
jsonGenerator.writeNumberField(propertyAndEncoder.getName(), Float.valueOf(value));
} catch (NumberFormatException e) {
serializeStringField(jsonGenerator, propertyAndEncoder, value);
}
}

private void serializeBooleanField(JsonGenerator jsonGenerator, AbstractPropertyAndEncoder<T> propertyAndEncoder, String value) throws IOException {
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
jsonGenerator.writeBooleanField(propertyAndEncoder.getName(), Boolean.valueOf(value));
} else {
serializeStringField(jsonGenerator, propertyAndEncoder, value);
}
}
}
Expand Up @@ -4,6 +4,11 @@ public class Property {
private String name;
private String value;
private boolean allowEmpty;
private Type type = Type.STRING;

public enum Type {
STRING, INT, FLOAT, BOOLEAN
}

public Property() {
}
Expand Down Expand Up @@ -37,4 +42,16 @@ public boolean isAllowEmpty() {
public void setAllowEmpty(boolean allowEmpty) {
this.allowEmpty = allowEmpty;
}

public Type getType() {
return type;
}

public void setType(String type) {
try {
this.type = Enum.valueOf(Type.class, type.toUpperCase());
} catch (IllegalArgumentException e) {
this.type = Type.STRING;
}
}
}
Expand Up @@ -31,4 +31,8 @@ public String getName() {
public boolean allowEmpty() {
return property.isAllowEmpty();
}

public Property.Type getType() {
return property.getType();
}
}
@@ -0,0 +1,141 @@
package com.internetitem.logback.elasticsearch;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Context;
import com.fasterxml.jackson.core.JsonGenerator;
import com.internetitem.logback.elasticsearch.config.Property;
import com.internetitem.logback.elasticsearch.util.ClassicPropertyAndEncoder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class PropertySerializerTest {
@Mock
private Context context;

@Mock
private JsonGenerator jsonGenerator;

@Mock
private ILoggingEvent loggingEvent;

private PropertySerializer<ILoggingEvent> propertySerializer = PropertySerializer.getInstance();

@Test
public void should_default_to_string_type() throws Exception {
// given
Property property = new Property();
property.setValue("propertyValue");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
assertThat(property.getType(), is(Property.Type.STRING));
verify(jsonGenerator).writeObject("propertyValue");
}

@Test
public void should_serialize_int_as_number() throws Exception {
// given
Property property = new Property();
property.setValue("123");
property.setType("int");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeNumber(123);
}

@Test
public void should_serialize_object_when_invalid_int() throws Exception {
// given
Property property = new Property();
property.setValue("A123Z");
property.setType("int");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeObject("A123Z");
}

@Test
public void should_serialize_float_as_number() throws Exception {
// given
Property property = new Property();
property.setValue("12.30");
property.setType("float");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeNumber(12.30f);
}

@Test
public void should_serialize_object_when_invalid_float() throws Exception {
// given
Property property = new Property();
property.setValue("A12.30Z");
property.setType("float");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeObject("A12.30Z");
}

@Test
public void should_serialize_true_as_boolean() throws Exception {
// given
Property property = new Property();
property.setValue("true");
property.setType("boolean");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeBoolean(true);
}

@Test
public void should_serialize_object_when_invalid_boolean() throws Exception {
// given
Property property = new Property();
property.setValue("AtrueZ");
property.setType("boolean");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeObject("AtrueZ");
}

@Test
public void should_serialize_object_when_invalid_type() throws Exception {
// given
Property property = new Property();
property.setValue("value");
property.setType("invalidType");

// when
propertySerializer.serializeProperty(jsonGenerator, loggingEvent, new ClassicPropertyAndEncoder(property, context));

// then
verify(jsonGenerator).writeObject("value");
}
}

0 comments on commit 6024368

Please sign in to comment.