Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove FastDateFormat #365

Conversation

Jimmy-653
Copy link

Replace FastDateFormat with DateTimeFormatter and Instant from java.time package

Copy link
Collaborator

@philsttr philsttr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I really appreciate contributions.

Unfortunately, I cannot accept these changes as-is. This change has removed the ability for logstash-logback-encoder to output timestamps as a json number (for number of milliseconds since unix epoch), and to output timestamps as a json string (representing the number of milliseconds since unix epoch), as documented here. Both of these are backwards-incompatible changes. I would rather not remove this functionality.

The switch from FastDateFormat to DateTimeFormatter is also a backwards-incompatible change due to the subtle differences between the patterns used by the two formatters, but I'm willing to accept this change in the next major release of logstash-logback-encoder. However, since logback does not support higher-precision timestamps yet, there is no rush to including this change in logstash-logback-encoder yet.

@@ -160,11 +96,11 @@ protected String getFormattedTimestamp(Event event) {
*/
private void updateTimestampWriter() {
if (UNIX_TIMESTAMP_AS_NUMBER.equals(pattern)) {
timestampWriter = new NumberTimestampWriter();
timestampWriter = null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a backwards incompatible change that I won't be able to accept.

logstash-logback-encoder still needs to optionally support writing timestamps as numbers indicating the number of milliseconds since unix epoch

Copy link
Author

@Jimmy-653 Jimmy-653 Oct 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this one, you have to take a close look at the overall change, or maybe I should remove UNIX_TIMESTAMP_AS_NUMBER completely because currently its only used in 2 test cases for it....
However, what was done previously, you would take the timestamp as milliseconds, convert them to a String, and then write it to the Json (inside the NumberTimestampWriter).

So actually im not using it anymore, I will remove it to clear confusion.
(Nothing lost here)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot remove the UNIX_TIMESTAMP_AS_NUMBER, or the NumberTimestampWriter.

The FormattedTimestampJsonProvider supports three scenarios:

UNIX_TIMESTAMP_AS_NUMBER will write the timestamp value as a json number indicating the number of milliseconds since unix epoch, like this:

{
    "@timestamp" : 1570901563
}

UNIX_TIMESTAMP_AS_STRING will write the timestamp value as a json string indicating the number of milliseconds since unix epoch, like this:

{
    "@timestamp" : "1570901563"
}

And any other pattern will be used as a format string. e.g.

{
    "@timestamp" : "2011-12-03T10:15:30+01:00"
}

From what I can tell, the new code always writes the timestamp value as a json string, which has effectively removed support for UNIX_TIMESTAMP_AS_NUMBER.

} else if (UNIX_TIMESTAMP_AS_STRING.equals(pattern)) {
timestampWriter = new StringTimestampWriter();
timestampWriter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN).withZone(TimeZone.getDefault().toZoneId());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a backwards incompatible change that I won't be able to accept.

logstash-logback-encoder still needs to optionally support writing timestamps as strings indicating the number of milliseconds since unix epoch

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missunderstood the StringTimestampWriter, I will take a second look

} else {
timestampWriter = new PatternTimestampWriter(FastDateFormat.getInstance(pattern, timeZone));
timestampWriter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()).withZone(TimeZone.getDefault().toZoneId());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are subtle differences in the pattern strings used by DateTimeFormatter and FastDateFormat, this is a backwards incompatible change. I'm willing to accept this change, but this will need a major version bump of logstash-logback-encoder.

I'll probably hold off on this until logback supports timestamps with higher precision.

@@ -200,7 +200,7 @@ public void unixTimestampAsNumber() throws Exception {

JsonNode node = MAPPER.readTree(encoded);

assertThat(node.get("@timestamp").numberValue()).isEqualTo(timestamp);
assertThat(node.get("@timestamp").asLong()).isEqualTo(timestamp);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my previous comment, this change will need to be reverted to ensure backwards compatibility. The json node should be a number value, not a string value that needs to be converted to a Long

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, Long is a type of Number? Its just the correct one already.

Copy link
Collaborator

@philsttr philsttr Oct 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not quite the same.

numberValue() will return the number if and only if the JsonNode represents a JSON number. This is the expected condition of this test case.

asLong() will convert String JsonNode values to a number. In this test case, the JsonNode is not expected contain a String value, so the test would incorrectly pass if the json node contained a string value.

In other words, the test should only pass if the json looks like this:

{
    "@timestamp" : 1570901563
}

The test should fail if the json looks like this:

{
    "@timestamp" : "1570901563"
}

@@ -70,12 +66,12 @@
public class LogstashEncoderTest {

private static Logger LOG = LoggerFactory.getLogger(LogstashEncoderTest.class);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be willing to revert all these whitespace changes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is annoying me aswell, I didnt had this change until I commited, something wrong in my Settings I guess, I will look into it.

assertThat(node.get("@timestamp").textValue()).isEqualTo(FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format
(timestamp));

assertThat(node.get("@timestamp").textValue()).isEqualTo(String.valueOf(timestamp));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. Why is the expected value here a long value converted to a string?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missunderstood the StringTimestampWriter, as a result I've done some wrong changes here

assertThat(output).isEqualTo(String.format(
"{%n"
+ " @timestamp : \"" + FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format(timestamp) + "\",%n"
+ " @timestamp : \"" + String.valueOf(timestamp) + "\",%n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. Why is the expected value here a long value converted to a string?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missunderstood the StringTimestampWriter, as a result I've done some wrong changes here

JsonNode node = MAPPER.readTree(encoded);

assertThat(node.get("@timestamp").textValue()).isEqualTo(FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format
(timestamp));
assertThat(node.get("@timestamp").textValue()).isEqualTo(String.valueOf(timestamp));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. Why is the expected value here a long value converted to a string?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missunderstood the StringTimestampWriter, as a result I've done some wrong changes here

assertThat(node.get("@timestamp").textValue()).isEqualTo(FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ", TimeZone.getTimeZone("UTC")).format
(timestamp));

assertThat(node.get("@timestamp").textValue()).isEqualTo(String.valueOf(timestamp));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above. Why is the expected value here a long value converted to a string?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missunderstood the StringTimestampWriter, as a result I've done some wrong changes here

} else {
timestampWriter = new PatternTimestampWriter(FastDateFormat.getInstance(pattern, timeZone));
timestampWriter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()).withZone(TimeZone.getDefault().toZoneId());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new code is always using the default timezone. It needs to take the configured timeZone into consideration like the old code.

@philsttr
Copy link
Collaborator

Closing this in favor of #377

Thanks @J-Jimmy for filing the issue, and contributing the PR. Even though I'm not accepting this PR directly, I used your contribution as a guide. I'll definitely call out your effort in the release notes when this is released.

@philsttr philsttr closed this Nov 23, 2019
@philsttr philsttr added this to the 7.0 milestone Jan 2, 2021
@philsttr philsttr added the warn/api-change Breaking change with compilation or xml configuration errors label Jan 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
warn/api-change Breaking change with compilation or xml configuration errors
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants