前言
当时接到要开发syslog功能时,我的表情是这样的…
啥是syslog啊?我没有听说过啊?这东西有什么用啊?懵逼三连…
然后问问我大佬,他说道syslog就是巴拉巴拉的说了一大堆,我全程嗯嗯啊啊的点头,然后大佬说完了问我听懂了吗?我回复听懂了其实我是这个样子的
我就听懂三点,第一要用java去开发,第二能支持TCP和UDP两种协议,还有可操控的,就这三点于是我开始了设计和研究啥是syslog日志服务器。
前期准备
这里写着需要准备的东西:
- 一双健全的手 ,能动就行;
- 编译器,ecplise或者idea都可以,我这里用的是ecplise;
- syslog解析jar包 这里用的是syslog4j的jar包,mvn项目的话maven地址 maven地址 提取码 mve8 jar地址
注意: 假如你本地maven项目引用的镜像是阿里云你可以将版本改为0.9.46,就像我这里
4.你要懂得syslog是什么,传送门
功能效果图
TCP服务器和TCP客户端运行结果:
TCP服务器和TCP客户端运行结果:
运用到项目里的结果:
操作页面:
接收到的数据只能输出到控制台的问题解决方法
这个问题困扰了我很久也一直百度但是没有找到任何的解决方法,在https://bbs.csdn.net/topics/392090474里有描述,可以复制一楼的代码运行试一试就知道了。主要问题是在于这个jar包的作者没有写出数据处理得方法,而该方法里的run里直接将信息给打印出来,不给一丝操作的机会。解决办法就是实现jar包里的SyslogServerSessionEventHandlerIF接口,然后去重写里面的event方法来达到的。该接口里提供了很多的方法,可以按照自己的需要去重写里面的方法来达到更好的效果。
具体代码
哔哔了这么久开始上代码
1.SyslogServerEventHandler类,为操作接收信息的类,继承SyslogServerSessionEventHandlerIF并重写event方法来达到。
public class SyslogServerEventHandler implements SyslogServerSessionEventHandlerIF {//extends PrintStreamSyslogServerEventHandler {
private String syslog ;
//重写event方法
public void event(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, SyslogServerEventIF event) {
//判断传输时间是否存在,不存在将现在的时间设置为传输时间
String date = (event.getDate() == null ? new Date() : event.getDate()).toString();
//将解析日志的生成端,<<3是要该数左移动三位计算
String facility = SyslogUtility.getFacilityString(event.getFacility()<<3);
//讲解析日志的级别,级别越大越低
String level = SyslogUtility.getLevelString(event.getLevel());
//获取当前的源设备IP
String sourceIP = getIPAddress(socketAddress.toString());
//获取到信息主体
String msg = event.getMessage();
//放入信息
setSyslog("{" + facility + "} " + date + " " + level + " " + event.getMessage()+ " " +sourceIP );
try {
//打印信息
System.out.println(getSyslog());
} catch (UnsupportedEncodingException e) {
System.err.println("UnsupportedEncodingException");
}
}
public String getSyslog() throws UnsupportedEncodingException {
return new String(syslog.getBytes(),"UTF-8");
}
public void setSyslog(String syslog) {
this.syslog = syslog;
}
//获取到该字符串里的ip地址
private String getIPAddress(String bString)
{
String regEx="((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(bString);
String result = "";
while (m.find()) {
result=m.group();
break;
}
return result;
}
@Override
public void initialize(SyslogServerIF syslogServer) {}
@Override
public void destroy(SyslogServerIF syslogServer) {}
@Override
public Object sessionOpened(SyslogServerIF syslogServer, SocketAddress socketAddress) {return null;}
@Override
public void exception(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress,Exception exception) {}
@Override
public void sessionClosed(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress,boolean timeout) {}
}
- TCP服务器 我喜欢用线程的方式启动,因为不用切来却去
public class TCPSyslogServerFinal implements Runnable {
private static TCPSyslogServerFinal TCPSyslogServerFinal = null;
//syslog服务器配置文件用于服务器关闭
private SyslogServerIF serverIf = null ;
public SyslogServerIF getServerIF() {
return serverIf;
}
private void setServerIF(SyslogServerIF serverIF) {
this.serverIf = serverIF;
}
private TCPSyslogServerFinal(){}
//用单例模式去书写
public static synchronized TCPSyslogServerFinal getTCPSyslogServer()
{
if(TCPSyslogServerFinal == null)
{
TCPSyslogServerFinal = new TCPSyslogServerFinal();
}
return TCPSyslogServerFinal;
}
@Override
public void run() {
//实例化接收处理方法
SyslogServerEventHandlerIF eventHandler = new SyslogServerEventHandler();
//传入TCP协议参数实例化具体服务器
SyslogServerIF serverIF = SyslogServer.getInstance("tcp");
//从服务器里获取配置信息变量
SyslogServerConfigIF config = serverIF.getConfig();
//设置监听地址0.0.0.0为监听网络内全部地址
config.setHost("0.0.0.0");
//设置监听地址为514,514为syslog默认地址
config.setPort(514);
//放入接收方法
config.addEventHandler(eventHandler);
//初始化服务器
serverIF.initialize("tcp",config);
System.out.println("server start tcp");
//设置服务器变量,用来外部调用关闭
setServerIF(serverIF);
//服务器启动
serverIF.run();
}
}
- UDP服务器 我喜欢用线程的方式启动,不同的地方就是在处传输的地方改为UDP
public class UDPSyslogServerFinal implements Runnable {
private static UDPSyslogServerFinal UDPSyslogServerFinal = null;
//syslog服务器配置文件用于服务器关闭
private SyslogServerIF serverIf = null ;
public SyslogServerIF getServerIF() {
return serverIf;
}
private void setServerIF(SyslogServerIF serverIF) {
this.serverIf = serverIF;
}
private UDPSyslogServerFinal(){}
//用单例模式去书写
public static synchronized UDPSyslogServerFinal getUDPSyslogServer()
{
if(UDPSyslogServerFinal == null)
{
UDPSyslogServerFinal = newUDPSyslogServerFinal();
}
return UDPSyslogServerFinal;
}
@Override
public void run() {
//实例化接收处理方法
SyslogServerEventHandlerIF eventHandler = new SyslogServerEventHandler();
//传入UDP协议参数实例化具体服务器 就是这个位置不同,如果你闲麻烦可以用自己优化一下算法然后将两个合为一个
SyslogServerIF serverIF = SyslogServer.getInstance("udp");
//从服务器里获取配置信息变量
SyslogServerConfigIF config = serverIF.getConfig();
//设置监听地址0.0.0.0为监听网络内全部地址
config.setHost("0.0.0.0");
//设置监听地址为514,514为syslog默认地址
config.setPort(514);
//放入接收方法
config.addEventHandler(eventHandler);
//初始化服务器
serverIF.initialize("udp",config);
System.out.println("server start udp");
//设置服务器变量,用来外部调用关闭
setServerIF(serverIF);
//服务器启动
serverIF.run();
}
}
4.客户端 ClientClass,我喜欢用线程的方式去实现
public class ClientClass implements Runnable{
//控制循环结束的
private boolean flag = true;
private static ClientClass ClientClass = null;
private ClientClass () {
}
public static synchronized ClientClass getClient()
{
if(ClientClass == null)
ClientClass = new ClientClass ();
return ClientClass ;
}
@Override
public void run() {
try {
//初始化标识位
flag = true;
//以传输名称的形势来传输实例化的协议类型
String prot = Thread.currentThread().getName();
//获取syslog的操作类,使用udp协议。syslog支持"udp", "tcp", "unix_syslog", "unix_socket"协议
SyslogIF syslog = Syslog.getInstance(prot);
//设置syslog服务器端地址 地址为之前你服务器的地址
syslog.getConfig().setHost("xx.xx.xx.xx");
//设置syslog接收端口,默认514
syslog.getConfig().setPort(514);
//拼接syslog日志
String str = "operator Protocol "+ Thread.currentThread().getName();
System.out.println("+++++++++++++start++++++++++++");
while(flag) {
//等级为debug
syslog.log(SyslogConstants.LEVEL_DEBUG, URLDecoder.decode(str,"utf-8"));
//给程序缓冲时间,没有缓冲时间接受不到数据
Thread.sleep(100);
}
System.out.println(Thread.currentThread().getName()+" end");
} catch (Exception e) {
System.err.println("出错了");
e.printStackTrace();
}
}
public void shutdown() {
try {
//线程停止
Thread.sleep(2000);
//改变标识位
flag = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5.测试类TestServerClass,运行main方法的测试类
@SuppressWarnings("unused")
public class TestServerClass implements Runnable{
public static void main(String[] args) throws Exception {
//获取UDP服务器线程
Thread UDPServer = new Thread(UDPSyslogServerFinal.getUDPSyslogServer(),"这是UDP服务器");
//获取TCP服务器线程
Thread TCPServer = new Thread(TCPSyslogServerFinal.getTCPSyslogServer(),"这是TCP服务器");
//获取UDP客户端线程
Thread UDPClient = new Thread(ClientClass.getClient(),"UDP");
//获取TCP客户端线程
Thread TCPClient = new Thread(ClientClass.getClient(),"TCP");
//启动线程
UDPServer.start();
UDPClient.start();
TCPServer.start();
TCPClient.start();
//运行十秒后关闭
Thread.sleep(10*1000);
//关闭服务器
UDPSyslogServerFinal.getUDPSyslogServer().getServerIF().shutdown();
TCPSyslogServerFinal.getTCPSyslogServer().getServerIF().shutdown();
//关闭客户端
ClientClass.getClient().shutdown();
}
}
结语
文章到这里就结束啦,写这个文章的初衷是因为自己想帮助那些想找java的syslog服务器却找不到的那些人。真的,在网上试着去百度、翻阅各种网站的博客都找不到解决的方法,这种感觉真的很崩溃。我的所有有灵感都来自于https://bbs.csdn.net/topics/392090474这个帖子,这个帖子到我发布的时候还是没有完结,所以我打算将解决方法写出来,然后去完结那个帖子,也希望能帮助那些看的人。