Skip to content

Commit

Permalink
add proper serialization for more JSR310 data types
Browse files Browse the repository at this point in the history
  • Loading branch information
cleaning-agent committed Aug 7, 2020
1 parent 56eb80d commit f405a19
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 11 deletions.
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ Structured logging utility.
* Works with log consumers that can digest JSON logs, like the **ELK Stack** or **Datadog**.
* Framework agnostic (works well with **Spring**, because Spring Boot uses logback out of the box)

**Table of Contents**

* [Why use this?](#why-use-this)
* [Example](#example)
* [Changes](#changes)
* [1.0.3](#103)
* [Usage](#usage)
* [Add structured-logging as a dependency](#add-structured-logging-as-a-dependency)
* [Define how Objects should be named in MDC](#define-how-objects-should-be-named-in-mdc)
* [Put Objects into MDC](#put-objects-into-mdc)
* [Excluding properties from serialization](#excluding-properties-from-serialization)
* [Configure Logback for Logstash](#configure-logback-for-logstash)
* [Configure a Task Decorator in Spring](#configure-a-task-decorator-in-spring)
* [Test your logging](#test-your-logging)

## Why use this?

If you use your logs for monitoring, alerting or visualization, you want them to have structured information so you can properly build your monitoring/alerting/visualizations on that.
Expand Down Expand Up @@ -42,6 +57,19 @@ If there are log messages that happen in the context of an order, you may want t
}
```

## Changes

### 1.0.3

* Added proper serialization for further JSR310 types. Now properly serializes
* Instant (new)
* LocalDate (new)
* LocalDateTime
* OffsetDateTime
* OffsetTime (new)
* Period (new)
* ZonedDateTime (new)

## Usage

To use this, you need to:
Expand All @@ -62,7 +90,7 @@ If you use maven, add this to your pom.xml:
<dependency>
<groupId>de.dm.infrastructure</groupId>
<artifactId>structured-logging</artifactId>
<version>1.0.2</version>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
```
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>de.dm.infrastructure</groupId>
<artifactId>structured-logging</artifactId>
<version>1.0.3-SNAPSHOT</version>
<version>1.0.4-SNAPSHOT</version>

<name>structured-logging</name>
<description>Structured logging and log testing</description>
Expand Down
26 changes: 19 additions & 7 deletions src/main/java/de/dm/prom/structuredlogging/MdcContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.lang.reflect.InvocationTargetException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Period;
import java.time.ZonedDateTime;

/**
* a context that can be used to wrap MDC information in a try-with-resources block.
Expand Down Expand Up @@ -56,14 +62,15 @@ private MdcContext(String key, String value) {
public void close() {
if (oldValue == null) {
MDC.remove(key);
}
else {
} else {
MDC.put(key, oldValue);
}
}

private static String toJson(Object object) {
String objectToJson = "{\"json_error\":\"Unserializable Object.\"}"; //needs to be an object, not a string, for Kibana. Otherwise, Kibana will throw away the log entry because the field has the wrong type.
String objectToJson = "{\"json_error\":\"Unserializable Object.\"}";
//needs to be an object, not a string, for Kibana. Otherwise, Kibana will throw away the log entry because the field has the wrong type.

try {
objectToJson = getObjectMapper().writeValueAsString(object);
} catch (JsonProcessingException e) {
Expand All @@ -73,10 +80,16 @@ private static String toJson(Object object) {
}

private static ObjectMapper getObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(OffsetDateTime.class, new ToStringSerializer());
module.addSerializer(Instant.class, new ToStringSerializer());
module.addSerializer(LocalDate.class, new ToStringSerializer());
module.addSerializer(LocalDateTime.class, new ToStringSerializer());
module.addSerializer(OffsetDateTime.class, new ToStringSerializer());
module.addSerializer(OffsetTime.class, new ToStringSerializer());
module.addSerializer(Period.class, new ToStringSerializer());
module.addSerializer(ZonedDateTime.class, new ToStringSerializer());

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
return objectMapper;
}
Expand All @@ -98,8 +111,7 @@ private static void logOverwriting(String key, String value, String oldValue) {
if (!oldValue.equals(value)) {
log.error("{} The old value differs from new value. This should never happen, because it messes up the MDC context. Old value: {} - new value: {}",
message, oldValue, value);
}
else {
} else {
log.warn("{} The value is overwritten with the same value. This is superfluous and should be removed.", message);
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/test/java/de/dm/prom/structuredlogging/ExampleBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
import lombok.Builder;
import lombok.Data;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

@Data
@Builder
Expand All @@ -15,6 +22,11 @@ class ExampleBean {
private int age;
private LocalDateTime importantTime;
private OffsetDateTime importantOffsetTime;
private Instant instant;
private LocalDate localDate;
private OffsetTime offsetTime;
private Period period;
private ZonedDateTime zonedDateTime;

static ExampleBean getExample() {
LocalDateTime importantTime = LocalDateTime.of(2019, Month.JANUARY, 1, 13, 37);
Expand All @@ -24,6 +36,11 @@ static ExampleBean getExample() {
.age(35)
.importantTime(importantTime)
.importantOffsetTime(OffsetDateTime.of(importantTime, ZoneOffset.of("+01:00")))
.instant(Instant.ofEpochMilli(1000))
.localDate(LocalDate.of(2020, 1, 1))
.offsetTime(OffsetTime.of(LocalTime.of(13, 37), ZoneOffset.of("+01:00")))
.period(Period.ofDays(42))
.zonedDateTime(ZonedDateTime.of(importantTime, ZoneId.of("UTC")))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@

@Slf4j
public class MdcContextUnitTest {
private static final String SAMPLE_BEAN_JSON = "{\"name\":\"John Doe\",\"age\":35,\"importantTime\":\"2019-01-01T13:37\",\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"}";
private static final String SAMPLE_BEAN_JSON = "{\"name\":\"John Doe\"," +
"\"age\":35," +
"\"importantTime\":\"2019-01-01T13:37\"," +
"\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"," +
"\"instant\":\"1970-01-01T00:00:01Z\"," +
"\"localDate\":\"2020-01-01\"," +
"\"offsetTime\":\"13:37+01:00\"," +
"\"period\":\"P42D\"," +
"\"zonedDateTime\":\"2019-01-01T13:37Z[UTC]\"}";

@Rule
public LogCapture logCapture = LogCapture.forUnitTest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@

@Slf4j
public class StructuredMdcJsonProviderUnitTest {
private static String SAMPLE_LOGSTASH_JSON_LOG = "{\"@version\":\"1\",\"message\":\"something in which the ExampleBean context is relevant\",\"logger_name\":\"de.dm.prom.structuredlogging.StructuredMdcJsonProviderUnitTest\",\"thread_name\":\"main\",\"level\":\"INFO\",\"level_value\":20000,\"an_unmanaged_mdc_field\":\"some value\",\"example_bean\":{\"name\":\"John Doe\",\"age\":35,\"importantTime\":\"2019-01-01T13:37\",\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"}}";
private static String SAMPLE_LOGSTASH_JSON_LOG = "{\"@version\":\"1\"," +
"\"message\":\"something in which the ExampleBean context is relevant\"," +
"\"logger_name\":\"de.dm.prom.structuredlogging.StructuredMdcJsonProviderUnitTest\"," +
"\"thread_name\":\"main\"," +
"\"level\":\"INFO\"," +
"\"level_value\":20000," +
"\"an_unmanaged_mdc_field\":\"some value\"," +
"\"example_bean\":" +
"{\"name\":\"John Doe\"," +
"\"age\":35," +
"\"importantTime\":\"2019-01-01T13:37\"," +
"\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"," +
"\"instant\":\"1970-01-01T00:00:01Z\"," +
"\"localDate\":\"2020-01-01\"," +
"\"offsetTime\":\"13:37+01:00\"," +
"\"period\":\"P42D\"," +
"\"zonedDateTime\":\"2019-01-01T13:37Z[UTC]\"}}";

private Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

@Rule
Expand Down

0 comments on commit f405a19

Please sign in to comment.