Skip to content

Commit

Permalink
Fix #37 - Fix RFC 3164 date padding: use for padding day of month…
Browse files Browse the repository at this point in the history
… instead of using `0`
  • Loading branch information
cyrille-leclerc committed Mar 4, 2020
1 parent 4c16653 commit fb0a208
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 18 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/cloudbees/syslog/SyslogMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import com.cloudbees.syslog.util.CachingReference;
import com.cloudbees.syslog.util.ConcurrentDateFormat;
import com.cloudbees.syslog.util.ConcurrentRfc3164DateFormat;

/**
* Syslog message as defined in <a href="https://tools.ietf.org/html/rfc5424">RFC 5424 - The Syslog Protocol</a>.
Expand All @@ -48,7 +49,7 @@ public class SyslogMessage {

private final static int DEFAULT_CONCURRENCY = 50;
protected final static ConcurrentDateFormat rfc3339DateFormat;
protected final static ConcurrentDateFormat rfc3164DateFormat;
protected final static ConcurrentRfc3164DateFormat rfc3164DateFormat;
private static CachingReference<String> localhostNameReference = new CachingReference<String>(10, TimeUnit.SECONDS) {
@Override
protected String newObject() {
Expand Down Expand Up @@ -81,9 +82,8 @@ protected String newObject() {
* The TIMESTAMP field is the local time and is in the format of "Mmm dd hh:mm:ss" (without the quote marks)
* </quote>
*/
rfc3164DateFormat = new ConcurrentDateFormat(
"MMM dd HH:mm:ss",
Locale.US,
rfc3164DateFormat = new ConcurrentRfc3164DateFormat(
Locale.getDefault(),
TimeZone.getDefault(),
concurrency);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.cloudbees.syslog.util;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import javax.annotation.Nonnull;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

/**
* https://tools.ietf.org/html/rfc3164#section-4.1.2
* <pre>
* The TIMESTAMP field is the local time and is in the format of "Mmm dd
* hh:mm:ss" (without the quote marks) where:
*
* Mmm is the English language abbreviation for the month of the
* year with the first character in uppercase and the other two
* characters in lowercase. The following are the only acceptable
* values:
*
* Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
*
* dd is the day of the month. If the day of the month is less
* than 10, then it MUST be represented as a space and then the
* number. For example, the 7th day of August would be
* represented as "Aug 7", with two spaces between the "g" and
* the "7".
*
* hh:mm:ss is the local time. The hour (hh) is represented in a
* 24-hour format. Valid entries are between 00 and 23,
* inclusive. The minute (mm) and second (ss) entries are between
* 00 and 59 inclusive.
* </pre>
*/
public class ConcurrentRfc3164DateFormat {
private final BlockingQueue<SimpleDateFormat> monthDateFormats;
private final BlockingQueue<SimpleDateFormat> timeDateFormats;
private final Locale locale;
private final TimeZone timeZone;

/**
* @param locale the locale whose date pattern symbols should be used
* @param timeZone the timezone used by the underlying calendar
* @param maxCacheSize
* @throws NullPointerException if the given pattern or locale is null
* @throws IllegalArgumentException if the given pattern is invalid
*/
public ConcurrentRfc3164DateFormat(Locale locale, TimeZone timeZone, int maxCacheSize) {
this.monthDateFormats = new LinkedBlockingDeque<>(maxCacheSize);
this.timeDateFormats = new LinkedBlockingDeque<>(maxCacheSize);
this.locale = locale;
this.timeZone = timeZone;
}

/**
* Formats a Date into a date/time string.
*
* @param date the time value to be formatted into a time string.
* @return the formatted time string.
*/
@Nonnull
@SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
public String format(@Nonnull Date date) {


// MONTH

String month;


// DAY OF MONTH
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);

int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
String dayofMonthPadding = dayOfMonth < 10 ? " " : "";

// TIME
SimpleDateFormat timeDateFormat = timeDateFormats.poll();
if (timeDateFormat == null) {
timeDateFormat = new SimpleDateFormat("HH:mm:ss", locale);
timeDateFormat.setTimeZone(timeZone);
}
String time;
try {
time = timeDateFormat.format(date);
} finally {
timeDateFormats.offer(timeDateFormat);
}

String result = month + ' ' + dayofMonthPadding + dayOfMonth + ' ' + time;

return result;
}

@Override
public String toString() {
return "ConcurrentRfc3164DateFormat";
}
}
39 changes: 33 additions & 6 deletions src/test/java/com/cloudbees/syslog/SyslogMessageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ public void testRfc5424FormatWithStructuredData() throws Exception {
System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime()));
System.out.println(cal.getTimeInMillis());


SyslogMessage message = new SyslogMessage()
.withTimestamp(cal.getTimeInMillis())
.withAppName("my_app")
Expand All @@ -119,15 +118,15 @@ public void testRfc5424FormatWithStructuredData() throws Exception {
}

@Test
public void testRfc3164Format() throws Exception {
public void testRfc3164Format_withTwoDigitsDay() throws Exception {

Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getDefault());
cal.set(2013, Calendar.DECEMBER, 5, 10, 30, 5);
cal.set(2013, Calendar.DECEMBER, 15, 10, 30, 5);
cal.set(Calendar.MILLISECOND, 0);

System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime()));
System.out.println(cal.getTimeInMillis());
// System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime()));
// System.out.println(cal.getTimeInMillis());


SyslogMessage message = new SyslogMessage()
Expand All @@ -140,9 +139,37 @@ public void testRfc3164Format() throws Exception {
.withMsg("a syslog message");

String actual = message.toRfc3164SyslogMessage();
String expected = "<14>Dec 05 10:30:05 myserver.example.com my_app: a syslog message";
String expected = "<14>Dec 15 10:30:05 myserver.example.com my_app: a syslog message";

assertThat(actual, is(expected));
}

/**
* https://tools.ietf.org/html/rfc3164#section-4.1.2
*/
@Test
public void testRfc3164Format_withSingleDigitDay() throws Exception {

Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getDefault());
cal.set(2013, Calendar.AUGUST, 7, 10, 30, 5);
cal.set(Calendar.MILLISECOND, 0);

// System.out.println(SyslogMessage.rfc3339DateFormat.format(cal.getTime()));
// System.out.println(cal.getTimeInMillis());

SyslogMessage message = new SyslogMessage()
.withTimestamp(cal.getTimeInMillis())
.withAppName("my_app")
.withHostname("myserver.example.com")
.withFacility(Facility.USER)
.withSeverity(Severity.INFORMATIONAL)
.withTimestamp(cal.getTimeInMillis())
.withMsg("a syslog message");

String actual = message.toRfc3164SyslogMessage();
String expected = "<14>Aug 7 10:30:05 myserver.example.com my_app: a syslog message";

assertThat(actual, is(expected));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,23 @@ public class TcpSyslogMessageSenderTest {
@Test
public void send() throws Exception {
TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender();
messageSender.setDefaultMessageHostname("mysecretkey");
// messageSender.setDefaultMessageHostname("mysecretkey");
messageSender.setDefaultAppName("myapp");
messageSender.setDefaultFacility(Facility.USER);
messageSender.setDefaultSeverity(Severity.INFORMATIONAL);
messageSender.setSyslogServerHostname("logs2.papertrailapp.com");
messageSender.setSyslogServerPort(46022);

// messageSender.setSyslogServerHostname("logs2.papertrailapp.com");
// messageSender.setSyslogServerPort(46022);
// messageSender.setSsl(true);

messageSender.setSyslogServerHostname("localhost");
messageSender.setSyslogServerPort(9000);

messageSender.setMessageFormat(MessageFormat.RFC_3164);
messageSender.setSsl(true);
messageSender.sendMessage("unit test message over tcp éèà " + getClass() + " - " + new Timestamp(System.currentTimeMillis()));
}

@Ignore
// @Ignore
@Test
public void send2() throws Exception {

Expand All @@ -57,10 +62,15 @@ public void send2() throws Exception {
.withTimestamp(System.currentTimeMillis());

TcpSyslogMessageSender messageSender = new TcpSyslogMessageSender();
messageSender.setSyslogServerHostname("logs2.papertrailapp.com");
messageSender.setSyslogServerPort(46022);

// messageSender.setSyslogServerHostname("logs2.papertrailapp.com");
// messageSender.setSyslogServerPort(46022);
// messageSender.setSsl(true);

messageSender.setSyslogServerHostname("localhost");
messageSender.setSyslogServerPort(9000);

messageSender.setMessageFormat(MessageFormat.RFC_3164);
messageSender.setSsl(true);

System.out.println(msg.toSyslogMessage(messageSender.getMessageFormat()));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.cloudbees.syslog.util;

import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class ConcurrentRfc3164DateFormatTest {

@Test
public void test_format_date_with_single_digit_day_of_month(){
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeZone(timeZone);
cal.set(2013, Calendar.AUGUST, 7, 10, 30, 5);
cal.set(Calendar.MILLISECOND, 0);

Date singleDigitDayOfMonthDate = cal.getTime();

ConcurrentRfc3164DateFormat rfc3164DateFormat = new ConcurrentRfc3164DateFormat(Locale.US, timeZone, 50);

String actual = rfc3164DateFormat.format(singleDigitDayOfMonthDate);

Assert.assertThat(actual, Matchers.is("Aug 7 10:30:05"));
}

@Test
public void test_format_date_with_double_digit_day_of_month(){
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeZone(timeZone);
cal.set(2013, Calendar.AUGUST, 17, 10, 30, 5);
cal.set(Calendar.MILLISECOND, 0);

Date singleDigitDayOfMonthDate = cal.getTime();

ConcurrentRfc3164DateFormat rfc3164DateFormat = new ConcurrentRfc3164DateFormat(Locale.US, timeZone, 50);

String actual = rfc3164DateFormat.format(singleDigitDayOfMonthDate);

Assert.assertThat(actual, Matchers.is("Aug 17 10:30:05"));
}
}

0 comments on commit fb0a208

Please sign in to comment.