reactor.io.net.codec.syslog.SyslogCodec Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2011-2014 Pivotal Software, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package reactor.io.net.codec.syslog;
import reactor.fn.Consumer;
import reactor.fn.Function;
import reactor.io.buffer.Buffer;
import reactor.io.codec.Codec;
import java.util.Calendar;
import java.util.Date;
/**
* A coded for consuming syslog messages. This codec produces no output, i.e. its encoding
* function returns {@code null}.
*
* @author Jon Brisbin
* @author Stephane Maldini
*/
public class SyslogCodec extends Codec {
private static final int MAXIMUM_SEVERITY = 7;
private static final int MAXIMUM_FACILITY = 23;
private static final int MINIMUM_PRI = 0;
private static final int MAXIMUM_PRI = (MAXIMUM_FACILITY * 8) + MAXIMUM_SEVERITY;
private static final int DEFAULT_PRI = 13;
@Override
public Buffer apply(Void v) {
return null;
}
@Override
public Function decoder(Consumer next) {
return new SyslogMessageDecoder(next);
}
private class SyslogMessageDecoder implements Function {
private final Calendar cal = Calendar.getInstance();
private final int year = cal.get(Calendar.YEAR);
private final Consumer next;
private Buffer.View remainder;
private SyslogMessageDecoder(Consumer next) {
this.next = next;
}
@Override
public SyslogMessage apply(Buffer buffer) {
return parse(buffer);
}
private SyslogMessage parse(Buffer buffer) {
String line = null;
if (null != remainder) {
line = remainder.get().asString();
}
int start = 0;
for (Buffer.View view : buffer.split('\n', false)) {
Buffer b = view.get();
if (b.last() != '\n') {
remainder = view;
return null;
}
String s = b.asString();
if (null != line) {
line += s;
} else {
line = s;
}
if (line.isEmpty()) {
continue;
}
int priority = DEFAULT_PRI;
int facility = priority / 8;
int severity = priority % 8;
int priStart = line.indexOf('<', start);
int priEnd = line.indexOf('>', start + 1);
if (priStart == 0) {
int pri = Buffer.parseInt(b, 1, priEnd);
if (pri >= MINIMUM_PRI && pri <= MAXIMUM_PRI) {
priority = pri;
facility = priority / 8;
severity = priority % 8;
}
start = 4;
}
Date tstamp = parseRfc3414Date(b, start, start + 15);
String host = null;
if (null != tstamp) {
start += 16;
int end = line.indexOf(' ', start);
host = line.substring(start, end);
if (null != host) {
start += host.length() + 1;
}
}
String msg = line.substring(start);
SyslogMessage syslogMsg = new SyslogMessage(line,
priority,
facility,
severity,
tstamp,
host,
msg);
if (null != next) {
next.accept(syslogMsg);
} else {
return syslogMsg;
}
line = null;
start = 0;
}
return null;
}
private Date parseRfc3414Date(Buffer b, int start, int end) {
b.snapshot();
b.byteBuffer().limit(end);
b.byteBuffer().position(start);
int month = -1;
int day = -1;
int hr = -1;
int min = -1;
int sec = -1;
switch (b.read()) {
case 'A': // Apr, Aug
switch (b.read()) {
case 'p':
month = Calendar.APRIL;
b.read();
break;
default:
month = Calendar.AUGUST;
b.read();
}
break;
case 'D': // Dec
month = Calendar.DECEMBER;
b.read();
b.read();
break;
case 'F': // Feb
month = Calendar.FEBRUARY;
b.read();
b.read();
break;
case 'J': // Jan, Jun, Jul
switch (b.read()) {
case 'a':
month = Calendar.JANUARY;
b.read();
break;
default:
switch (b.read()) {
case 'n':
month = Calendar.JUNE;
break;
default:
month = Calendar.JULY;
}
}
break;
case 'M': // Mar, May
b.read();
switch (b.read()) {
case 'r':
month = Calendar.MARCH;
break;
default:
month = Calendar.MAY;
}
break;
case 'N': // Nov
month = Calendar.NOVEMBER;
b.read();
b.read();
break;
case 'O': // Oct
month = Calendar.OCTOBER;
b.read();
b.read();
break;
case 'S': // Sep
month = Calendar.SEPTEMBER;
b.read();
b.read();
break;
default:
return null;
}
while (b.read() == ' ') {
}
int dayStart = b.position() - 1;
while (b.read() != ' ') {
}
int dayEnd = b.position() - 1;
day = Buffer.parseInt(b, dayStart, dayEnd);
while (b.read() == ' ') {
}
int timeStart = b.position() - 1;
hr = Buffer.parseInt(b, timeStart, timeStart + 2);
min = Buffer.parseInt(b, timeStart + 3, timeStart + 5);
sec = Buffer.parseInt(b, timeStart + 6, timeStart + 8);
try {
if (month < 0 || day < 0 || hr < 0 || min < 0 || sec < 0) {
return null;
} else {
cal.set(year, month, day, hr, min, sec);
return cal.getTime();
}
} finally {
b.reset();
}
}
}
}