/* * Copyright 2002-2016 the original author or authors. * * 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 org.springframework.integration.transformer; import java.io.UnsupportedEncodingException; import java.sql.Date; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.LinkedHashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Transforms a packet in Syslog (RFC3164) format to a Map. * If the packet cannot be decoded, the entire packet * is returned as a String under the key {@code UNDECODED}. If the date field can be * parsed, it will be returned as a {@link Date} object; otherwise it is returned as a String. * * @author Gary Russell * @author Artem Bilan * @author Karol Dowbecki * @since 2.2 * */ public class SyslogToMapTransformer extends AbstractPayloadTransformer<Object, Map<String, ?>> { private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd HH:mm:ss"); public static final String FACILITY = "FACILITY"; public static final String SEVERITY = "SEVERITY"; public static final String TIMESTAMP = "TIMESTAMP"; public static final String HOST = "HOST"; public static final String TAG = "TAG"; public static final String MESSAGE = "MESSAGE"; public static final String UNDECODED = "UNDECODED"; private final Pattern pattern = Pattern.compile("<([^>]+)>(.{15}) ([^ ]+) ([a-zA-Z0-9]{0,32})(.*)", Pattern.DOTALL); @Override protected Map<String, ?> transformPayload(Object payload) throws Exception { boolean isByteArray = payload instanceof byte[]; boolean isString = payload instanceof String; Assert.isTrue(isByteArray || isString, "payload must be String or byte[]"); if (isByteArray) { return this.transform((byte[]) payload); } else if (isString) { return this.transform((String) payload); } return null; } private Map<String, ?> transform(byte[] payloadBytes) { String payload; try { payload = new String(payloadBytes, "UTF-8"); } catch (UnsupportedEncodingException e) { payload = new String(payloadBytes); } return transform(payload); } private Map<String, ?> transform(String payload) { Map<String, Object> map = new LinkedHashMap<String, Object>(); Matcher matcher = this.pattern.matcher(payload); if (matcher.matches()) { try { String facilityString = matcher.group(1); int facility = Integer.parseInt(facilityString); int severity = facility & 0x7; facility = facility >> 3; map.put(FACILITY, facility); map.put(SEVERITY, severity); String timestamp = matcher.group(2); try { LocalDate localDate = this.dateTimeFormatter.parse(timestamp, LocalDate::from); Calendar calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); calendar.setTime(Date.valueOf(localDate)); /* * syslog date doesn't include a year so we * need to insert the current year - adjusted * if necessary if close to midnight on Dec 31. */ if (month == 11 && calendar.get(Calendar.MONTH) == 0) { calendar.set(Calendar.YEAR, year + 1); } else if (month == 0 && calendar.get(Calendar.MONTH) == 1) { calendar.set(Calendar.YEAR, year - 1); } else { calendar.set(Calendar.YEAR, year); } map.put(TIMESTAMP, calendar.getTime()); } catch (Exception e) { /* * If we can't parse the timestamp, return it as an * unmodified String. (Postel's law). */ map.put(TIMESTAMP, timestamp); } map.put(HOST, matcher.group(3)); if (StringUtils.hasLength(matcher.group(4))) { map.put(TAG, matcher.group(4)); } map.put(MESSAGE, matcher.group(5)); } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("Could not decode:" + payload, e); } map.clear(); map.put(UNDECODED, payload); } } else { if (logger.isDebugEnabled()) { logger.debug("Could not decode:" + payload); } map.put(UNDECODED, payload); } return map; } }