/*
* Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
* Copyright (c) 2016 TethrNet Technology Co.Ltd and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.tsdr.syslogs;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.tsdr.syslogs.filters.SyslogFilterManager;
import org.opendaylight.tsdr.syslogs.server.SyslogTCPServer;
import org.opendaylight.tsdr.syslogs.server.SyslogUDPServer;
import org.opendaylight.tsdr.syslogs.server.datastore.SyslogDatastoreManager;
import org.opendaylight.tsdr.syslogs.server.decoder.Message;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.tsdr.collector.spi.rev150915.InsertTSDRLogRecordInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.tsdr.collector.spi.rev150915.TsdrCollectorSpiService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.tsdr.collector.spi.rev150915.inserttsdrlogrecord.input.TSDRLogRecord;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.tsdr.syslog.collector.rev151007.TsdrSyslogCollectorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.DatagramSocket;
import java.util.LinkedList;
import java.util.List;
/**
* This Class start both TCP and UDP servers
* to receive syslog messages and claim how
* TSDR database handle the messages.
*
* @author Sharon Aicler(saichler@gmail.com)
* @author Kun Chen(kunch@tethrnet.com)
**/
public class TSDRSyslogCollectorImpl implements BindingAwareProvider {
public static final int UDP_PORT = 514;
public static final int TCP_PORT = 6514;
public static final long QUEUE_WAIT_INTERVAL = 2000;
public static final long STORE_FLUSH_INTERVAL = 2500;
SyslogTCPServer tcpServer;
SyslogUDPServer udpServer;
private TsdrCollectorSpiService collectorSPIService = null;
private boolean running = true;
private Logger logger = LoggerFactory.getLogger(TSDRSyslogCollectorImpl.class);
private List<TSDRLogRecord> syslogQueue = new LinkedList<TSDRLogRecord>();
private final List<Message> messageList = new LinkedList<Message>();
private SyslogFilterManager filterManager = new SyslogFilterManager();
private long lastPersisted = System.currentTimeMillis();
private int udpPort = UDP_PORT;
private int tcpPort = TCP_PORT;
private int coreThreadPoolSize = 5;
private int maxThreadPoolSize = 10;
private long keepAliveTime = 10L;
private int queueSize = 10;
private DataBroker dataBroker;
private SyslogDatastoreManager manager;
private BindingAwareBroker.RpcRegistration<TsdrSyslogCollectorService> syslogsvrService;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/***
* constructor of collector
*
* @param _collectorSPIService invoke collector SPI service to implement tsdr data insertion
*/
public TSDRSyslogCollectorImpl(TsdrCollectorSpiService _collectorSPIService) {
this.collectorSPIService = _collectorSPIService;
this.manager = SyslogDatastoreManager.getInstance(coreThreadPoolSize, maxThreadPoolSize, keepAliveTime, queueSize);
new SyslogProcessor().start();
}
public void setUdpPort(int udpPort) {
this.udpPort = udpPort;
}
public void setTcpPort(int tcpPort) {
this.tcpPort = tcpPort;
}
public void setCoreThreadPoolSize(int coreThreadPoolSize) {
this.coreThreadPoolSize = coreThreadPoolSize;
}
public void setKeepAliveTime(long keepAliveTime) {
this.keepAliveTime = keepAliveTime;
}
public void setMaxThreadPoolSize(int maxThreadPoolSize) {
this.maxThreadPoolSize = maxThreadPoolSize;
}
public void setQueueSize(int queueSize) {
this.queueSize = queueSize;
}
public void setManager(SyslogDatastoreManager manager) {
this.manager = manager;
}
public boolean isRunning() {
return this.running;
}
/**
* initiated when the data binding broker is registered
* in TSDRSyslogModule
*
* @param session binding aware broker's provider context
*/
@Override
public void onSessionInitiated(BindingAwareBroker.ProviderContext session) {
this.dataBroker = session.getSALService(DataBroker.class);
manager.setDataBroker(dataBroker);
logger.info("Datastore Manager Setup Done");
this.syslogsvrService = session.addRpcImplementation(TsdrSyslogCollectorService.class, manager);
logger.info("Register SyslogsvrService to Session.");
logger.info("Syslog Collector Session Initiated");
//Start TCP syslog server
logger.info("Start TCP server");
try {
tcpServer = new SyslogTCPServer(this.messageList);
tcpServer.setPort(tcpPort);
tcpServer.startServer();
logger.info("TCP server started at port: " + tcpPort + ".");
} catch (Exception e) {
logger.error(e.getMessage());
this.close();
}
//Test If port is available
boolean udpPortAvailable = false;
try {
DatagramSocket socket = new DatagramSocket(udpPort);
socket.close();
socket = null;
udpPortAvailable = true;
} catch (Exception e) {
logger.error("Port " + udpPort + " is not available for UDP, trying backup...");
try {
udpPort += 1000;
DatagramSocket socket = new DatagramSocket(udpPort);
socket.close();
socket = null;
udpPortAvailable = true;
} catch (Exception err) {
this.close();
logger.error("Port " + udpPort + " is not available, not starting servers!");
}
}
if (udpPortAvailable) {
//Start UDP syslog server
logger.info("Start UDP server");
try {
udpServer = new SyslogUDPServer(messageList);
udpServer.setPort(udpPort);
udpServer.startServer();
logger.info("UDP server started at port: " + udpPort + ".");
} catch (Exception e) {
logger.error("Failed to start UDP server on port " + udpPort, e);
}
}
}
public void close() {
running = false;
try {
if (tcpServer != null)
tcpServer.stopServer();
if (udpServer != null)
udpServer.stopServer();
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
private class SyslogProcessor extends Thread {
public SyslogProcessor() {
super("TSDR Syslog Processor");
this.setDaemon(true);
}
public void run() {
Message message = null;
while (running) {
synchronized (messageList) {
if (messageList.isEmpty()) {
try {
messageList.wait(QUEUE_WAIT_INTERVAL);
} catch (InterruptedException e) {
}
}
if (!messageList.isEmpty()) {
message = messageList.remove(0);
}
}
if (message != null) {
TSDRLogRecord logRecord = filterManager.applyFilters(message);
if (logRecord != null) {
syslogQueue.add(logRecord);
}
}
if (System.currentTimeMillis() - lastPersisted > STORE_FLUSH_INTERVAL && !syslogQueue.isEmpty()) {
List<TSDRLogRecord> queue = null;
synchronized (filterManager) {
//Currently there is only one SyslogProcessor thread so this check seems meaningless
//If the future if we decide to have a few of those we need to make sure the queue
//has something and the interval has passed inside the synchronize block.
if (System.currentTimeMillis() - lastPersisted > STORE_FLUSH_INTERVAL && !syslogQueue.isEmpty()) {
lastPersisted = System.currentTimeMillis();
queue = syslogQueue;
syslogQueue = new LinkedList<>();
}
}
if (queue != null) {
store(queue);
}
}
message = null;
}
}
}
private void store(List<TSDRLogRecord> queue) {
InsertTSDRLogRecordInputBuilder input = new InsertTSDRLogRecordInputBuilder();
input.setTSDRLogRecord(queue);
input.setCollectorCodeName("SyslogCollector");
collectorSPIService.insertTSDRLogRecord(input.build());
}
public int getUdpPort() {
return this.udpPort;
}
public int getTcpPort() {
return this.tcpPort;
}
}