创建电信网络实时监控图
――电信网管中的Java客户端系列(四)
在电信网管系统的五大模块PCAPS中,性能管理(Performance Management)是非常重要的部分。性能管理是对电信网络的有效监控手段,是实现网络“提前预警”或“主动式告警”的基础。
性能管理一般分为历史性能数据和实时数据采集两类。历史性能数据一般需要网管后台系统的任务调度模块按照预定义的系统配置参数启动数据采集任务,并将数据采集结果存储到数据库中,以供用户进行统计、分析之用。实时性能数据一般由用户主动发起和终止,系统按照当前任务参数进行实时的数据采集,并将数据呈现。实时性能数据可选择存库,也可选择不存库,只作为瞬态数据进行呈现。实时性能数据也可挂接业务判断规则,以便生成告警或者各种动作。
本文将针对电信网管中的实时数据的采集、呈现、自动触发动作等开发做一个初步的探讨。
本文示例分别使用JFreeChart和TWaver作为图表组件和网络拓扑组件的界面呈现。JFreeChart是一款开源的优秀的Java图表工具,其网站地址是http:// www.jfree.org/jfreechart/。TWaver是一款强大的电信网管界面组件工具包,具有完善的功能、优秀的系统架构和运行效率。其试用版软件的下载地址为:http://www.servasoft.com/downloads.htm。
一般而言,实时性能数据采集的发起者是客户端。用户通过客户端指定感兴趣的网络设备或者管理对象,并选择感兴趣的具体参数、采集周期等信息,最终形成一个采集任务。启动后,客户端将通过服务器对指定数据进行采集,并将结果返回到客户端进行呈现。
由于本文只关注客户端的呈现部分,所以只讨论如何将要采集的数据和网络管理对象进行关联和管理,及其呈现。
我们在创建网络管理对象的数据模型过程中,需要对网络数据进行相关的建模。我们可用创建新的类并继承自TWaver的预定义节点对象,例如:
public class MyEquipment extends twaver.Node {
public MyEquipment(){}
public MyEquipment(Object id){
super(id);
}
…
public void setParameter1(Object param1){…}
public Object getParameter1(){return param1;}
}
通过以上代码,我们创建了一个简单的节点管理对象,并增加了新的属性parameter1。但是我们很快发现,对于一个实际应用中的网络设备或管理对象,其性能参数是数量庞大的,而且种类多样。我们如果通过java beans的方式进行编码,代码将非常罗嗦烦杂,而且也无法处理一些动态的数据。幸运的是TWaver为我们提供了一种“动态属性”机制。我们可以在运行期间动态的对数据进行添加、删除和访问:
Node myNode=new Node();
//设置采集数据
myNode.putClientProperty(“oper_status”, “up”);
//访问采集数据
//myNode.getClientProperty(“oper_status”);
通过以上方法,我们就可以让管理对象方便的携带任意数量和类型的性能数据,而无需预先定义。
当一个管理对象的数据被性能采集轮询模块不断的更新的时候,我们在客户端如何用最简单、可靠、有效的方法进行监控其变化呢?这个很简单,在TWaver中,我们可以使用一个网络元素属性监听器(Element Property Listener)来完成。
TWaver是通过一个数据箱(DataBox)容器来装载所有的网络对象的。一旦对象放入数据箱后,数据箱将对每一个对象进行监控,包括其属性的变化,甚至动态属性(即通过putClientProperty方法放入的数据)的变化。我们可以在数据箱上面加装一个属性监听器,即可对每一个网络对象进行属性监听:
TDataBox box=new TDataBox();
box.addElement(new Node());
…
box.addElementPropertyChangeListener(new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent e){
//获得事件发生源,也就是管理对象
Element element=(Element)e.getSource();
//获得变化的属性名称
String propertyName=e.getPropertyName();
//获得属性old值
Object oldValue=e.getOldValue();
//获得属性new值
Object newValue=e.getNewValue();
//然后就可以显示chart图了
…
}
});
可见,TWaver通过标准的java.beans包定义的PropertyChangeListener和PropertyChangeEvent来通知网络管理对象的属性变化,使用起来非常简单和容易理解。并且在结构上也更加的MVC,容易扩展。当然我们也可以加装多个监听器分别对不同的对象进行监听,并作出不同的相应动作。
我们使用JFreeChart来呈现运行状态下网络管理对象性能数据的变化。我们通过以下代码创建一个多维的曲线图:
JFreeChart jfreechart = ChartFactory.createTimeSeriesChart(
"Monitor Demo",
"Time",
"Value",
xydataset,
true,
true,
false);
XYPlot xyplot = jfreechart.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
xyplot.addRangeMarker(this.createIntervalMarker(0, 20, Color.GREEN, "0~20"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(20, 40, Color.BLACK, "20~40"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(40, 60, Color.PINK, "40~60"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(60, 80, Color.BLUE, "60~80"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(80, 10000, Color.YELLOW, "80~10000"), Layer.BACKGROUND);
然后,在属性监听器获得数据更新的使用,使用以下代码将新的数据append到chart图中:
series.add(new org.jfree.data.time.Hour(newTime), value);
就完成了对属性的监听。怎么样,非常简单吧?
以下通过一个完整的示例展现通过JFreeChart和TWaver来呈现网络性能实时数据采集和呈现。
package test;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.*;
import org.jfree.data.time.*;
import org.jfree.data.xy.*;
import org.jfree.ui.*;
import twaver.*;
import twaver.network.*;
public class Monitor extends JFrame {
int i = 1;
private final static String CLIENT_PROPERTY_NAME = "performance";
class DataGenerator extends Timer implements ActionListener {
Random random = new Random();
DataGenerator(int i) {
super(i, null);
addActionListener(this);
}
public void actionPerformed(ActionEvent actionevent) {
Element element = box.getElement("L");
element.putClientProperty(CLIENT_PROPERTY_NAME, new Integer(random.nextInt(100)));
}
}
private JFreeChart createChart(XYDataset xydataset) {
JFreeChart jfreechart = ChartFactory.createTimeSeriesChart(
"Monitor Demo",
"Time",
"Value",
xydataset,
true,
true,
false);
XYPlot xyplot = jfreechart.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
xyplot.addRangeMarker(this.createIntervalMarker(0, 20, Color.GREEN, "0~20"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(20, 40, Color.BLACK, "20~40"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(40, 60, Color.PINK, "40~60"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(60, 80, Color.BLUE, "60~80"), Layer.BACKGROUND);
xyplot.addRangeMarker(this.createIntervalMarker(80, 10000, Color.YELLOW, "80~10000"), Layer.BACKGROUND);
return jfreechart;
}
private IntervalMarker createIntervalMarker(double low, double height, Color color, String label) {
IntervalMarker intervalmarker = new IntervalMarker(low, height);
intervalmarker.setPaint(color);
intervalmarker.setLabel(label);
intervalmarker.setLabelFont(TWaverConst.DEFAULT_ZH_FONT);
intervalmarker.setLabelAnchor(RectangleAnchor.LEFT);
intervalmarker.setLabelTextAnchor(TextAnchor.CENTER_LEFT);
return intervalmarker;
}
DataGenerator generator = new DataGenerator(500);
TDataBox box = new TDataBox();
TNetwork network = new TNetwork(box);
TimeSeries series = new TimeSeries("element property value", org.jfree.data.time.Hour.class);
public Monitor() {
Node node1 = new Node("A");
node1.setLocation(100, 100);
node1.setName("start");
box.addElement(node1);
Node node2 = new Node("B");
node2.setLocation(500, 200);
node2.setName("end");
box.addElement(node2);
Link link = new Link("L", node1, node2);
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_WIDTH, new Integer(6));
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING, Boolean.TRUE);
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.black);
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_COLOR, Color.white);
box.addElement(link);
TimeSeriesCollection timeseriescollection = new TimeSeriesCollection(series);
ChartPanel chartpanel = new ChartPanel(createChart(timeseriescollection));
chartpanel.setPreferredSize(new Dimension(700, 300));
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().add(network, BorderLayout.CENTER);
this.getContentPane().add(chartpanel, BorderLayout.SOUTH);
this.setSize(700, 600);
box.addElementPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
Element element = (Element) evt.getSource();
String propertyName = evt.getPropertyName();
if (element instanceof Link &&
(TWaverConst.ELEMENT_CLIENT_PROPERTY_PREFIX + CLIENT_PROPERTY_NAME).equals(propertyName)) {
Link link = (Link) element;
int value = ((Integer) evt.getNewValue()).intValue();
link.setName(CLIENT_PROPERTY_NAME + ":" + value);
if (0 <= value && value < 20) {
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.GREEN);
}
if (20 <= value && value < 40) {
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.BLACK);
}
if (40 <= value && value < 60) {
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.PINK);
}
if (60 <= value && value < 80) {
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.BLUE);
}
if (80 <= value) {
link.putClientProperty(TWaverConst.PROPERTYNAME_LINK_FLOWING_COLOR, Color.YELLOW);
}
Date newTime = new Date(new Date().getTime() + (i++) * 3600 * 1000);
System.out.println(newTime.toLocaleString());
series.add(new org.jfree.data.time.Hour(newTime), value);
}
}
});
generator.start();
}
public static void main(String[] args) {
Monitor test = new Monitor();
test.show();
}
}
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"></shapetype><stroke joinstyle="miter"></stroke><formulas></formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f><lock v:ext="edit" aspectratio="t"></lock><shape id="_x0000_i1025" style="WIDTH: 385.5pt; HEIGHT: 366pt" type="#_x0000_t75"></shape><imagedata src="file:///C:%5Ctemp%5Cmsohtml1%5C01%5Cclip_image001.png" o:title=""></imagedata>