From 58dea07515958765733cad6da0b29133f45e3684 Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Wed, 24 Feb 2016 13:21:48 +0900 Subject: [PATCH 01/11] heap max/used chart --- .../netio/request/handle/AgentThread.java | 4 + scouter.client/plugin.xml | 16 + .../counter/actions/OpenPTPairAllAction.java | 60 +++ .../counter/actions/OpenRTPairAllAction.java | 39 ++ .../counter/views/CounterPTAllPairChart.java | 386 +++++++++++++++++ .../counter/views/CounterRTAllPairChart.java | 397 ++++++++++++++++++ .../src/scouter/client/util/MenuUtil.java | 2 + 7 files changed, 904 insertions(+) create mode 100644 scouter.client/src/scouter/client/counter/actions/OpenPTPairAllAction.java create mode 100644 scouter.client/src/scouter/client/counter/actions/OpenRTPairAllAction.java create mode 100644 scouter.client/src/scouter/client/counter/views/CounterPTAllPairChart.java create mode 100644 scouter.client/src/scouter/client/counter/views/CounterRTAllPairChart.java diff --git a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentThread.java b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentThread.java index c79554fb5..d6f41b3d0 100644 --- a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentThread.java +++ b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentThread.java @@ -131,6 +131,8 @@ public Pack activeThreadList(Pack param) { ListValue ip = rPack.newList("ip"); ListValue sql = rPack.newList("sql"); ListValue subcall = rPack.newList("subcall"); + ListValue login = rPack.newList("login"); + ListValue desc = rPack.newList("desc"); Enumeration en = TraceContextManager.getContextEnumeration(); while (en.hasMoreElements()) { TraceContext ctx = en.nextElement(); @@ -154,6 +156,8 @@ public Pack activeThreadList(Pack param) { Logger.println("A128", th); cpu.add(0L); } + login.add(ctx.login); + desc.add(ctx.desc); } rPack.put("complete", new BooleanValue(true)); return rPack; diff --git a/scouter.client/plugin.xml b/scouter.client/plugin.xml index 526a6e107..9e039bc0f 100644 --- a/scouter.client/plugin.xml +++ b/scouter.client/plugin.xml @@ -942,6 +942,22 @@ name="Visitors" restorable="false"> + + + + diff --git a/scouter.client/src/scouter/client/counter/actions/OpenPTPairAllAction.java b/scouter.client/src/scouter/client/counter/actions/OpenPTPairAllAction.java new file mode 100644 index 000000000..80df9057f --- /dev/null +++ b/scouter.client/src/scouter/client/counter/actions/OpenPTPairAllAction.java @@ -0,0 +1,60 @@ +package scouter.client.counter.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.Images; +import scouter.client.counter.views.CounterPTAllPairChart; +import scouter.client.popup.CalendarDialog; +import scouter.client.popup.CalendarDialog.ILoadCalendarDialog; +import scouter.client.util.ConsoleProxy; +import scouter.client.util.ImageUtil; +import scouter.client.util.TimeUtil; +import scouter.util.DateUtil; + +public class OpenPTPairAllAction extends Action implements ILoadCalendarDialog { + + IWorkbenchWindow window; + int serverId; + String objType; + String counter; + + public OpenPTPairAllAction(IWorkbenchWindow window, String name, int serverId, String objType, String counter) { + this.window = window; + this.serverId = serverId; + this.objType = objType; + this.counter = counter; + setImageDescriptor(ImageUtil.getImageDescriptor(Images.calendar)); + setText(name); + } + + public void run() { + CalendarDialog dialog = new CalendarDialog(window.getShell().getDisplay(), this); + dialog.showWithTime(-1, -1, TimeUtil.getCurrentTime(serverId) - DateUtil.MILLIS_PER_FIVE_MINUTE); + } + + public void onPressedOk(long startTime, long endTime) { + if (window != null) { + try { + CounterPTAllPairChart chart = (CounterPTAllPairChart) window.getActivePage().showView( + CounterPTAllPairChart.ID, serverId + "&" + objType + "&" + counter , + IWorkbenchPage.VIEW_ACTIVATE); + if (chart != null) { + chart.setInput(startTime, endTime); + } + } catch (PartInitException e) { + ConsoleProxy.errorSafe("Error opening view:" + e.getMessage()); + } + } + } + + public void onPressedOk(String date) { + + } + + public void onPressedCancel() { + + } +} diff --git a/scouter.client/src/scouter/client/counter/actions/OpenRTPairAllAction.java b/scouter.client/src/scouter/client/counter/actions/OpenRTPairAllAction.java new file mode 100644 index 000000000..8fb9facee --- /dev/null +++ b/scouter.client/src/scouter/client/counter/actions/OpenRTPairAllAction.java @@ -0,0 +1,39 @@ +package scouter.client.counter.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.Images; +import scouter.client.counter.views.CounterRTAllPairChart; +import scouter.client.util.ConsoleProxy; + +public class OpenRTPairAllAction extends Action { + + IWorkbenchWindow window; + int serverId; + String objType; + String counter; + + public OpenRTPairAllAction(IWorkbenchWindow window, String name, int serverId, String objType, String counter) { + this.window = window; + this.serverId = serverId; + this.objType = objType; + this.counter = counter; + setImageDescriptor(Images.getCounterImageDescriptor(objType, counter, serverId)); + setText(name); + } + + public void run() { + if (window != null) { + try { + window.getActivePage().showView( + CounterRTAllPairChart.ID, serverId + "&" + objType + "&" + counter , + IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException e) { + ConsoleProxy.errorSafe("Error opening view:" + e.getMessage()); + } + } + } +} diff --git a/scouter.client/src/scouter/client/counter/views/CounterPTAllPairChart.java b/scouter.client/src/scouter/client/counter/views/CounterPTAllPairChart.java new file mode 100644 index 000000000..9daaa2618 --- /dev/null +++ b/scouter.client/src/scouter/client/counter/views/CounterPTAllPairChart.java @@ -0,0 +1,386 @@ +package scouter.client.counter.views; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.csstudio.swt.xygraph.dataprovider.CircularBufferDataProvider; +import org.csstudio.swt.xygraph.dataprovider.ISample; +import org.csstudio.swt.xygraph.dataprovider.Sample; +import org.csstudio.swt.xygraph.figures.Trace; +import org.csstudio.swt.xygraph.figures.Trace.PointStyle; +import org.csstudio.swt.xygraph.figures.Trace.TraceType; +import org.csstudio.swt.xygraph.figures.XYGraph; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.draw2d.FigureCanvas; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.window.DefaultToolTip; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.counter.actions.OpenPTPairAllAction; +import scouter.client.listeners.RangeMouseListener; +import scouter.client.model.AgentColorManager; +import scouter.client.model.TextProxy; +import scouter.client.net.INetReader; +import scouter.client.net.TcpProxy; +import scouter.client.preferences.PManager; +import scouter.client.preferences.PreferenceConstants; +import scouter.client.server.Server; +import scouter.client.server.ServerManager; +import scouter.client.threads.ObjectSelectManager; +import scouter.client.threads.ObjectSelectManager.IObjectCheckListener; +import scouter.client.util.ChartUtil; +import scouter.client.util.ColorUtil; +import scouter.client.util.ConsoleProxy; +import scouter.client.util.CounterUtil; +import scouter.client.util.ExUtil; +import scouter.client.util.ScouterUtil; +import scouter.client.views.ScouterViewPart; +import scouter.io.DataInputX; +import scouter.lang.counters.CounterEngine; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.lang.value.Value; +import scouter.lang.value.ValueEnum; +import scouter.net.RequestCmd; +import scouter.util.CastUtil; +import scouter.util.DateUtil; +import scouter.util.FormatUtil; +import scouter.util.StringUtil; + +public class CounterPTAllPairChart extends ScouterViewPart implements IObjectCheckListener { + + public final static String ID = CounterPTAllPairChart.class.getName(); + + private int serverId; + private String objType; + private String counter; + private long stime; + private long etime; + + protected XYGraph xyGraph; + protected Map dataMap = new HashMap(); + TracePair nearestTracePair; + protected FigureCanvas canvas; + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + String[] ids = StringUtil.split(secId, "&"); + this.serverId = CastUtil.cint(ids[0]); + this.objType = ids[1]; + this.counter = ids[2]; + } + + public void createPartControl(Composite parent) { + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 5; + layout.marginWidth = 5; + parent.setLayout(layout); + parent.setBackground(ColorUtil.getInstance().getColor(SWT.COLOR_WHITE)); + parent.setBackgroundMode(SWT.INHERIT_FORCE); + + canvas = new FigureCanvas(parent); + canvas.setLayoutData(new GridData(GridData.FILL_BOTH)); + canvas.setScrollBarVisibility(FigureCanvas.NEVER); + canvas.addControlListener(new ControlListener() { + boolean lock = false; + + public void controlResized(ControlEvent e) { + org.eclipse.swt.graphics.Rectangle r = canvas.getClientArea(); + if (!lock) { + lock = true; + if (ChartUtil.isShowDescriptionAllowSize(r.height)) { + CounterPTAllPairChart.this.setContentDescription(desc); + } else { + CounterPTAllPairChart.this.setContentDescription(""); + } + r = canvas.getClientArea(); + xyGraph.setSize(r.width, r.height); + lock = false; + } + } + + public void controlMoved(ControlEvent e) { + } + }); + + xyGraph = new XYGraph(); + xyGraph.setShowLegend(false); + xyGraph.setShowTitle(false); + canvas.setContents(xyGraph); + + xyGraph.primaryXAxis.setDateEnabled(true); + xyGraph.primaryXAxis.setShowMajorGrid(true); + + xyGraph.primaryYAxis.setAutoScale(true); + xyGraph.primaryYAxis.setShowMajorGrid(true); + + xyGraph.primaryXAxis.setTitle(""); + xyGraph.primaryYAxis.setTitle(""); + + xyGraph.primaryXAxis.setFormatPattern("HH:mm:ss"); + xyGraph.primaryYAxis.setFormatPattern("#,##0"); + + xyGraph.primaryYAxis.addMouseListener(new RangeMouseListener(getViewSite().getShell(), xyGraph.primaryYAxis)); + + final DefaultToolTip toolTip = new DefaultToolTip(canvas, DefaultToolTip.RECREATE, true); + toolTip.setFont(new Font(null, "Arial", 10, SWT.BOLD)); + toolTip.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + + canvas.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + if (nearestTracePair != null) { + int width = PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH); + nearestTracePair.setLineWidth(width); + nearestTracePair = null; + } + toolTip.hide(); + } + public void mouseDown(MouseEvent e) { + double x = xyGraph.primaryXAxis.getPositionValue(e.x, false); + double y = xyGraph.primaryYAxis.getPositionValue(e.y, false); + if (x < 0 || y < 0) { + return; + } + double minDistance = 30.0d; + long time = 0; + double max = 0; + double value = 0; + Iterator keys = dataMap.keySet().iterator(); + while (keys.hasNext()) { + int objHash = keys.next(); + TracePair tp = dataMap.get(objHash); + Trace t1 = tp.t1; + ISample s1 = ScouterUtil.getNearestPoint(t1.getDataProvider(), x); + Trace t2 = tp.t2; + ISample s2 = ScouterUtil.getNearestPoint(t2.getDataProvider(), x); + if (s1 != null && s2 != null) { + int x1 = xyGraph.primaryXAxis.getValuePosition(s1.getXValue(), false); + int y1 = xyGraph.primaryYAxis.getValuePosition(s1.getYValue(), false); + int x2 = xyGraph.primaryXAxis.getValuePosition(s2.getXValue(), false); + int y2 = xyGraph.primaryYAxis.getValuePosition(s2.getYValue(), false); + double distance1 = ScouterUtil.getPointDistance(e.x, e.y, x1, y1); + double distance2 = ScouterUtil.getPointDistance(e.x, e.y, x2, y2); + double distance = distance1 > distance2 ? distance2 : distance1; + if (minDistance > distance) { + minDistance = distance; + nearestTracePair = tp; + time = (long) s1.getXValue(); + max = s1.getYValue(); + value = s2.getYValue(); + } + } + + } + if (nearestTracePair != null) { + int width = PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH); + nearestTracePair.setLineWidth(width + 2); + toolTip.setText(TextProxy.object.getText(nearestTracePair.objHash) + + "\nTime : " + DateUtil.format(time, "HH:mm:ss") + + "\nMax : " + FormatUtil.print(max, "#,###.##") + + "\nValue : " + FormatUtil.print(value, "#,###.##")); + toolTip.show(new Point(e.x, e.y)); + } + } + public void mouseDoubleClick(MouseEvent e) {} + }); + + IToolBarManager man = getViewSite().getActionBars().getToolBarManager(); + man.add(new OpenPTPairAllAction(getViewSite().getWorkbenchWindow(), "Load", serverId, objType, counter)); + + ObjectSelectManager.getInstance().addObjectCheckStateListener(this); + } + + public void setInput(long stime, long etime) { + this.stime = stime; + this.etime = etime; + try { + setViewTab(objType, counter, serverId); + Server server = ServerManager.getInstance().getServer(serverId); + CounterEngine ce = server.getCounterEngine(); + String counterName = ce.getCounterDisplayName(objType, counter); + desc = "ⓢ" + server.getName() + " | (Past All) " + counterName + "(" + ce.getCounterUnit(objType, counter) + ") " + + DateUtil.format(stime, "yyyyMMdd HH:mm:ss") + " ~ " + DateUtil.format(etime, "HH:mm:ss"); + this.xyGraph.primaryXAxis.setRange(stime, etime); + } catch (Exception e1) { + e1.printStackTrace(); + } + Set keySet = dataMap.keySet(); + for (Integer key : keySet) { + TracePair tp = dataMap.get(key); + xyGraph.removeTrace(tp.t1); + xyGraph.removeTrace(tp.t2); + } + dataMap.clear(); + load(); + } + + private void load() { + CounterEngine counterEngine = ServerManager.getInstance().getServer(serverId).getCounterEngine(); + new Job("Load " + counterEngine.getCounterDisplayName(objType, counter)) { + protected IStatus run(IProgressMonitor monitor) { + final List values = new ArrayList(); + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + try { + MapPack param = new MapPack(); + param.put("stime", stime); + param.put("etime", etime); + param.put("objType", objType); + param.put("counter", counter); + + tcp.process(RequestCmd.COUNTER_PAST_TIME_ALL, param, new INetReader() { + public void process(DataInputX in) throws IOException { + MapPack mpack = (MapPack) in.readPack(); + values.add(mpack); + }; + }); + } catch (Throwable t) { + ConsoleProxy.errorSafe(t.toString()); + } finally { + TcpProxy.putTcpProxy(tcp); + } + + ExUtil.exec(canvas, new Runnable() { + public void run() { + double max = 0; + for (MapPack mpack : values) { + int objHash = mpack.getInt("objHash"); + ListValue time = mpack.getList("time"); + ListValue value = mpack.getList("value"); + TracePair tp = getTracePair(objHash); + CircularBufferDataProvider maxProvider = (CircularBufferDataProvider) tp.t1.getDataProvider(); + CircularBufferDataProvider valueProvider = (CircularBufferDataProvider) tp.t2.getDataProvider(); + maxProvider.clearTrace(); + valueProvider.clearTrace(); + for (int i = 0; time != null && i < time.size(); i++) { + long x = time.getLong(i); + Value v = value.get(i); + if (v != null && v.getValueType() == ValueEnum.LIST) { + ListValue lv = (ListValue) v; + maxProvider.addSample(new Sample(x, lv.getDouble(0))); + valueProvider.addSample(new Sample(x, lv.getDouble(1))); + } + } + max = Math.max(ChartUtil.getMax(maxProvider.iterator()), max); + } + if (CounterUtil.isPercentValue(objType, counter)) { + xyGraph.primaryYAxis.setRange(0, 100); + } else { + xyGraph.primaryYAxis.setRange(0, max); + } + redraw(); + } + }); + + return Status.OK_STATUS; + } + + }.schedule(); + } + + public void notifyChangeState() { + ExUtil.asyncRun(new Runnable() { + public void run() { + for (TracePair tp : dataMap.values()) { + if (ObjectSelectManager.getInstance().isUnselectedObject(tp.objHash)) { + tp.setVisible(false); + } else { + tp.setVisible(true); + } + } + ExUtil.exec(canvas, new Runnable() { + public void run() { + redraw(); + } + }); + } + }); + } + + private TracePair getTracePair(int objHash) { + TracePair tp = dataMap.get(objHash); + if (tp == null) { + tp = new TracePair(); + tp.objHash = objHash; + + CircularBufferDataProvider data1 = new CircularBufferDataProvider(true); + data1.setBufferSize((int) ((etime - stime) / (DateUtil.MILLIS_PER_SECOND * 2))); + data1.setCurrentXDataArray(new double[] {}); + data1.setCurrentYDataArray(new double[] {}); + String name = StringUtil.trimToEmpty(TextProxy.object.getLoadText( + DateUtil.yyyymmdd(stime), objHash, + serverId)); + Trace trace1 = new Trace(name+"(Max)", xyGraph.primaryXAxis, xyGraph.primaryYAxis, data1); + trace1.setPointStyle(PointStyle.NONE); + trace1.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + trace1.setTraceType(TraceType.SOLID_LINE); + trace1.setTraceColor(AgentColorManager.getInstance().assignColor(objType, objHash)); + xyGraph.addTrace(trace1); + tp.t1 = trace1; + + CircularBufferDataProvider data2 = new CircularBufferDataProvider(true); + data2.setBufferSize((int) ((etime - stime) / (DateUtil.MILLIS_PER_SECOND * 2))); + data2.setCurrentXDataArray(new double[] {}); + data2.setCurrentYDataArray(new double[] {}); + Trace trace2 = new Trace(name+"(Value)", xyGraph.primaryXAxis, xyGraph.primaryYAxis, data2); + trace2.setPointStyle(PointStyle.NONE); + trace2.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + trace2.setTraceType(TraceType.SOLID_LINE); + trace2.setTraceColor(AgentColorManager.getInstance().assignColor(objType, objHash)); + xyGraph.addTrace(trace2); + tp.t2 = trace2; + + dataMap.put(objHash, tp); + } + return tp; + } + + @Override + public void dispose() { + super.dispose(); + ObjectSelectManager.getInstance().removeObjectCheckStateListener(this); + } + + public void redraw() { + if (canvas != null && canvas.isDisposed() == false) { + canvas.redraw(); + xyGraph.repaint(); + } + } + + private static class TracePair { + int objHash; + Trace t1; + Trace t2; + + public void setLineWidth(int width) { + if (t1 != null) t1.setLineWidth(width); + if (t2 != null) t2.setLineWidth(width); + } + + public void setVisible(boolean visible) { + if (t1 != null) t1.setVisible(visible); + if (t2 != null) t2.setVisible(visible); + } + } +} diff --git a/scouter.client/src/scouter/client/counter/views/CounterRTAllPairChart.java b/scouter.client/src/scouter/client/counter/views/CounterRTAllPairChart.java new file mode 100644 index 000000000..50053b7ff --- /dev/null +++ b/scouter.client/src/scouter/client/counter/views/CounterRTAllPairChart.java @@ -0,0 +1,397 @@ +package scouter.client.counter.views; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.csstudio.swt.xygraph.dataprovider.CircularBufferDataProvider; +import org.csstudio.swt.xygraph.dataprovider.ISample; +import org.csstudio.swt.xygraph.dataprovider.Sample; +import org.csstudio.swt.xygraph.figures.Trace; +import org.csstudio.swt.xygraph.figures.Trace.PointStyle; +import org.csstudio.swt.xygraph.figures.Trace.TraceType; +import org.csstudio.swt.xygraph.figures.XYGraph; +import org.csstudio.swt.xygraph.linearscale.Range; +import org.eclipse.draw2d.FigureCanvas; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.window.DefaultToolTip; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.counter.actions.OpenPTPairAllAction; +import scouter.client.listeners.RangeMouseListener; +import scouter.client.maria.actions.OpenDbDailyConnView; +import scouter.client.model.AgentColorManager; +import scouter.client.model.RefreshThread; +import scouter.client.model.RefreshThread.Refreshable; +import scouter.client.model.TextProxy; +import scouter.client.net.TcpProxy; +import scouter.client.preferences.PManager; +import scouter.client.preferences.PreferenceConstants; +import scouter.client.server.Server; +import scouter.client.server.ServerManager; +import scouter.client.threads.ObjectSelectManager; +import scouter.client.threads.ObjectSelectManager.IObjectCheckListener; +import scouter.client.util.ChartUtil; +import scouter.client.util.ColorUtil; +import scouter.client.util.ConsoleProxy; +import scouter.client.util.CounterUtil; +import scouter.client.util.ExUtil; +import scouter.client.util.ScouterUtil; +import scouter.client.util.TimeUtil; +import scouter.client.views.ScouterViewPart; +import scouter.lang.counters.CounterEngine; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.lang.value.Value; +import scouter.lang.value.ValueEnum; +import scouter.net.RequestCmd; +import scouter.util.CastUtil; +import scouter.util.DateUtil; +import scouter.util.FormatUtil; +import scouter.util.StringUtil; + +public class CounterRTAllPairChart extends ScouterViewPart implements Refreshable, IObjectCheckListener { + + public final static String ID = CounterRTAllPairChart.class.getName(); + + protected RefreshThread thread = null; + + private int serverId; + private String objType; + private String counter; + + protected XYGraph xyGraph; + protected Map dataMap = new HashMap(); + TracePair nearestTracePair; + protected FigureCanvas canvas; + boolean isActive = false; + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + String[] ids = StringUtil.split(secId, "&"); + this.serverId = CastUtil.cint(ids[0]); + this.objType = ids[1]; + this.counter = ids[2]; + } + + public void createPartControl(Composite parent) { + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 5; + layout.marginWidth = 5; + parent.setLayout(layout); + parent.setBackground(ColorUtil.getInstance().getColor(SWT.COLOR_WHITE)); + parent.setBackgroundMode(SWT.INHERIT_FORCE); + + canvas = new FigureCanvas(parent); + canvas.setLayoutData(new GridData(GridData.FILL_BOTH)); + canvas.setScrollBarVisibility(FigureCanvas.NEVER); + canvas.addControlListener(new ControlListener() { + boolean lock = false; + + public void controlResized(ControlEvent e) { + org.eclipse.swt.graphics.Rectangle r = canvas.getClientArea(); + if (!lock) { + lock = true; + if (ChartUtil.isShowDescriptionAllowSize(r.height)) { + CounterRTAllPairChart.this.setContentDescription(desc); + } else { + CounterRTAllPairChart.this.setContentDescription(""); + } + r = canvas.getClientArea(); + xyGraph.setSize(r.width, r.height); + lock = false; + } + } + + public void controlMoved(ControlEvent e) { + } + }); + + xyGraph = new XYGraph(); + xyGraph.setShowLegend(false); + xyGraph.setShowTitle(false); + canvas.setContents(xyGraph); + + xyGraph.primaryXAxis.setDateEnabled(true); + xyGraph.primaryXAxis.setShowMajorGrid(true); + + xyGraph.primaryYAxis.setAutoScale(true); + xyGraph.primaryYAxis.setShowMajorGrid(true); + + xyGraph.primaryXAxis.setTitle(""); + xyGraph.primaryYAxis.setTitle(""); + + xyGraph.primaryXAxis.setFormatPattern("HH:mm:ss"); + xyGraph.primaryYAxis.setFormatPattern("#,##0"); + + xyGraph.primaryYAxis.addMouseListener(new RangeMouseListener(getViewSite().getShell(), xyGraph.primaryYAxis)); + + final DefaultToolTip toolTip = new DefaultToolTip(canvas, DefaultToolTip.RECREATE, true); + toolTip.setFont(new Font(null, "Arial", 10, SWT.BOLD)); + toolTip.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + + canvas.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + if (nearestTracePair != null) { + int width = PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH); + nearestTracePair.setLineWidth(width); + nearestTracePair = null; + } + toolTip.hide(); + } + public void mouseDown(MouseEvent e) { + double x = xyGraph.primaryXAxis.getPositionValue(e.x, false); + double y = xyGraph.primaryYAxis.getPositionValue(e.y, false); + if (x < 0 || y < 0) { + return; + } + double minDistance = 30.0d; + long time = 0; + double max = 0; + double value = 0; + Iterator keys = dataMap.keySet().iterator(); + while (keys.hasNext()) { + int objHash = keys.next(); + TracePair tp = dataMap.get(objHash); + Trace t1 = tp.t1; + ISample s1 = ScouterUtil.getNearestPoint(t1.getDataProvider(), x); + Trace t2 = tp.t2; + ISample s2 = ScouterUtil.getNearestPoint(t2.getDataProvider(), x); + if (s1 != null && s2 != null) { + int x1 = xyGraph.primaryXAxis.getValuePosition(s1.getXValue(), false); + int y1 = xyGraph.primaryYAxis.getValuePosition(s1.getYValue(), false); + int x2 = xyGraph.primaryXAxis.getValuePosition(s2.getXValue(), false); + int y2 = xyGraph.primaryYAxis.getValuePosition(s2.getYValue(), false); + double distance1 = ScouterUtil.getPointDistance(e.x, e.y, x1, y1); + double distance2 = ScouterUtil.getPointDistance(e.x, e.y, x2, y2); + double distance = distance1 > distance2 ? distance2 : distance1; + if (minDistance > distance) { + minDistance = distance; + nearestTracePair = tp; + time = (long) s1.getXValue(); + max = s1.getYValue(); + value = s2.getYValue(); + } + } + + } + if (nearestTracePair != null) { + int width = PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH); + nearestTracePair.setLineWidth(width + 2); + toolTip.setText(TextProxy.object.getText(nearestTracePair.objHash) + + "\nTime : " + DateUtil.format(time, "HH:mm:ss") + + "\nMax : " + FormatUtil.print(max, "#,###.##") + + "\nValue : " + FormatUtil.print(value, "#,###.##")); + toolTip.show(new Point(e.x, e.y)); + } + } + public void mouseDoubleClick(MouseEvent e) {} + }); + + ObjectSelectManager.getInstance().addObjectCheckStateListener(this); + try { + setViewTab(objType, counter, serverId); + Server server = ServerManager.getInstance().getServer(serverId); + CounterEngine ce = server.getCounterEngine(); + String counterName = ce.getCounterDisplayName(objType, counter); + desc = "ⓢ" + server.getName() + " | (Current All) " + counterName + "(" + ce.getCounterUnit(objType, counter) + ")"; + } catch (Exception e1) { + e1.printStackTrace(); + } + + IToolBarManager man = getViewSite().getActionBars().getToolBarManager(); + man.add(new OpenPTPairAllAction(getViewSite().getWorkbenchWindow(), "Load", serverId, objType, counter)); + + thread = new RefreshThread(this, 2000); + thread.setName(this.toString() + " - " + "objType:" + objType + ", counter:" + counter + ", serverId:" + serverId); + thread.start(); + } + + public void notifyChangeState() { + ExUtil.asyncRun(new Runnable() { + public void run() { + for (TracePair tp : dataMap.values()) { + if (ObjectSelectManager.getInstance().isUnselectedObject(tp.objHash)) { + tp.setVisible(false); + } else { + tp.setVisible(true); + } + } + ExUtil.exec(canvas, new Runnable() { + public void run() { + redraw(); + } + }); + } + }); + } + + private TracePair getTracePair(int objHash) { + TracePair tp = dataMap.get(objHash); + if (tp == null) { + tp = new TracePair(); + tp.objHash = objHash; + + CircularBufferDataProvider data1 = new CircularBufferDataProvider(true); + data1.setBufferSize(155); + data1.setCurrentXDataArray(new double[] {}); + data1.setCurrentYDataArray(new double[] {}); + String name = StringUtil.trimToEmpty(TextProxy.object.getLoadText( + DateUtil.yyyymmdd(TimeUtil.getCurrentTime(serverId)), objHash, + serverId)); + Trace trace1 = new Trace(name+"(Max)", xyGraph.primaryXAxis, xyGraph.primaryYAxis, data1); + trace1.setPointStyle(PointStyle.NONE); + trace1.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + trace1.setTraceType(TraceType.SOLID_LINE); + trace1.setTraceColor(AgentColorManager.getInstance().assignColor(objType, objHash)); + xyGraph.addTrace(trace1); + tp.t1 = trace1; + + CircularBufferDataProvider data2 = new CircularBufferDataProvider(true); + data2.setBufferSize(155); + data2.setCurrentXDataArray(new double[] {}); + data2.setCurrentYDataArray(new double[] {}); + Trace trace2 = new Trace(name+"(Value)", xyGraph.primaryXAxis, xyGraph.primaryYAxis, data2); + trace2.setPointStyle(PointStyle.NONE); + trace2.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + trace2.setTraceType(TraceType.SOLID_LINE); + trace2.setTraceColor(AgentColorManager.getInstance().assignColor(objType, objHash)); + xyGraph.addTrace(trace2); + tp.t2 = trace2; + + dataMap.put(objHash, tp); + } + return tp; + } + + private double getMaxValue() { + Iterator objHashs = dataMap.keySet().iterator(); + double max = 0.0; + Range xRange = xyGraph.primaryXAxis.getRange(); + double lower = xRange.getLower(); + double upper = xRange.getUpper(); + while (objHashs.hasNext()) { + int objHash = objHashs.next(); + CircularBufferDataProvider data = (CircularBufferDataProvider) dataMap.get(objHash).t1.getDataProvider(); + if (data != null) { + for (int inx = 0; inx < data.getSize(); inx++) { + Sample sample = (Sample) data.getSample(inx); + double x = sample.getXValue(); + if(x < lower || x > upper) { + continue; + } + double y = sample.getYValue(); + if (y > max) { + max = y; + } + } + } + } + return ChartUtil.getMaxValue(max); + } + + public void refresh() { + final HashMap values = new HashMap(); + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + try { + MapPack param = new MapPack(); + + param.put("objType", objType); + param.put("counter", counter); + + MapPack out = (MapPack) tcp.getSingle(RequestCmd.COUNTER_REAL_TIME_ALL, param); + isActive = false; + if (out != null) { + ListValue objHash = out.getList("objHash"); + ListValue v = out.getList("value"); + for (int i = 0; i < objHash.size(); i++) { + values.put(CastUtil.cint(objHash.get(i)), v.get(i)); + isActive = true; + } + } + } catch (Throwable t) { + ConsoleProxy.errorSafe(t.toString()); + } finally { + TcpProxy.putTcpProxy(tcp); + } + + ExUtil.exec(canvas, new Runnable() { + public void run() { + if (isActive) { + setActive(); + } else { + setInactive(); + } + + long now = TimeUtil.getCurrentTime(serverId); + xyGraph.primaryXAxis.setRange(now - DateUtil.MILLIS_PER_MINUTE * 5, now + 1); + Iterator itr = values.keySet().iterator(); + while (itr.hasNext()) { + int objHash = itr.next(); + Value value = values.get(objHash); + if (value != null && value.getValueType() == ValueEnum.LIST) { + ListValue lv = (ListValue) value; + TracePair tp = getTracePair(objHash); + CircularBufferDataProvider provider1 = (CircularBufferDataProvider) tp.t1.getDataProvider(); + CircularBufferDataProvider provider2 = (CircularBufferDataProvider) tp.t2.getDataProvider(); + provider1.addSample(new Sample(now, CastUtil.cdouble(lv.get(0)))); + provider2.addSample(new Sample(now, CastUtil.cdouble(lv.get(1)))); + } + + } + if (CounterUtil.isPercentValue(objType, counter)) { + xyGraph.primaryYAxis.setRange(0, 100); + } else { + double max = getMaxValue(); + xyGraph.primaryYAxis.setRange(0, max); + } + redraw(); + } + }); + } + + @Override + public void dispose() { + super.dispose(); + if (this.thread != null) { + this.thread.shutdown(); + } + ObjectSelectManager.getInstance().removeObjectCheckStateListener(this); + } + + public void redraw() { + if (canvas != null && canvas.isDisposed() == false) { + canvas.redraw(); + xyGraph.repaint(); + } + } + + private static class TracePair { + int objHash; + Trace t1; + Trace t2; + + public void setLineWidth(int width) { + if (t1 != null) t1.setLineWidth(width); + if (t2 != null) t2.setLineWidth(width); + } + + public void setVisible(boolean visible) { + if (t1 != null) t1.setVisible(visible); + if (t2 != null) t2.setVisible(visible); + } + } +} diff --git a/scouter.client/src/scouter/client/util/MenuUtil.java b/scouter.client/src/scouter/client/util/MenuUtil.java index 1d32c160f..200278059 100644 --- a/scouter.client/src/scouter/client/util/MenuUtil.java +++ b/scouter.client/src/scouter/client/util/MenuUtil.java @@ -69,6 +69,7 @@ import scouter.client.counter.actions.OpenPastTimeAllAction; import scouter.client.counter.actions.OpenPastTimeTotalAction; import scouter.client.counter.actions.OpenPastTimeViewAction; +import scouter.client.counter.actions.OpenRTPairAllAction; import scouter.client.counter.actions.OpenRealTimeAllAction; import scouter.client.counter.actions.OpenRealTimeMultiAction; import scouter.client.counter.actions.OpenRealTimeStackAction; @@ -489,6 +490,7 @@ public void menuAboutToShow(IMenuManager mgr) { public static void addObjTypeSpecialMenu(IWorkbenchWindow win, IMenuManager mgr, int serverId, String objType, CounterEngine counterEngine) { if (counterEngine.isChildOf(objType, CounterConstants.FAMILY_JAVAEE)) { mgr.add(new Separator()); + mgr.add(new OpenRTPairAllAction(win, "Heap Memory", serverId, objType, CounterConstants.JAVA_HEAP_TOT_USAGE)); mgr.add(new OpenEQViewAction(win, serverId, objType)); mgr.add(new OpenActiveServiceListAction(win, objType, Images.thread, serverId)); mgr.add(new OpenActiveSpeedAction(win,objType, Images.TYPE_ACTSPEED, serverId)); From 076574c48d87b91c6b1599c51cd4cd9203ead692 Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Wed, 24 Feb 2016 13:22:52 +0900 Subject: [PATCH 02/11] realtime cpu usage to avgerage10sec --- .../agent/counter/meter/MeterResource.java | 70 +++++++++++++++++++ .../scouter/agent/counter/task/HostPerf.java | 17 ++++- 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 scouter.agent.host/src/scouter/agent/counter/meter/MeterResource.java diff --git a/scouter.agent.host/src/scouter/agent/counter/meter/MeterResource.java b/scouter.agent.host/src/scouter/agent/counter/meter/MeterResource.java new file mode 100644 index 000000000..09b9c5edb --- /dev/null +++ b/scouter.agent.host/src/scouter/agent/counter/meter/MeterResource.java @@ -0,0 +1,70 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.agent.counter.meter; + +import scouter.lang.ref.DOUBLE; +import scouter.lang.ref.INT; +import scouter.util.MeteringUtil; +import scouter.util.MeteringUtil.Handler; + +public class MeterResource { + + static class Bucket { + double value; + int count; + } + private MeteringUtil meter = new MeteringUtil() { + protected Bucket create() { + return new Bucket(); + }; + + protected void clear(Bucket o) { + o.value=0; + o.count = 0; + } + }; + + public synchronized void add(double value) { + Bucket b = meter.getCurrentBucket(); + b.value += value; + b.count++; + } + + public double getAvg(int period) { + final INT count = new INT(); + final DOUBLE sum = new DOUBLE(); + meter.search(period, new Handler() { + public void process(Bucket u) { + sum.value += u.value; + count.value += u.count; + } + }); + return count.value == 0 ? 0 : sum.value / count.value; + } + + public double getSum(int period) { + final DOUBLE sum = new DOUBLE(); + meter.search(period, new Handler() { + public void process(Bucket u) { + sum.value += u.value; + } + }); + return sum.value; + } + +} \ No newline at end of file diff --git a/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java b/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java index c022b151c..da17b6a0a 100644 --- a/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java +++ b/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java @@ -16,6 +16,7 @@ import scouter.agent.Logger; import scouter.agent.counter.CounterBasket; import scouter.agent.counter.anotation.Counter; +import scouter.agent.counter.meter.MeterResource; import scouter.agent.netio.data.DataProxy; import scouter.lang.AlertLevel; import scouter.lang.TimeTypeEnum; @@ -31,7 +32,11 @@ public class HostPerf { static int SLEEP_TIME = 2000; static Sigar sigarImpl = new Sigar(); static SigarProxy sigar = SigarProxyCache.newInstance(sigarImpl, SLEEP_TIME); - + + MeterResource cpuMeter = new MeterResource(); + MeterResource sysCpuMeter = new MeterResource(); + MeterResource userCpuMeter = new MeterResource(); + @Counter public void process(CounterBasket pw) { try { @@ -48,10 +53,18 @@ void domain(CounterBasket pw) throws SigarException { CpuPerc cpuPerc = sigar.getCpuPerc(); float cpu = (float) ((1.0D - cpuPerc.getIdle()) * 100); - alertCpu(cpu); + cpuMeter.add(cpu); float sysCpu = (float) cpuPerc.getSys() * 100; + sysCpuMeter.add(sysCpu); float userCpu = (float) cpuPerc.getUser() * 100; + userCpuMeter.add(userCpu); + + cpu = (float) cpuMeter.getAvg(10); + sysCpu = (float) sysCpuMeter.getAvg(10); + userCpu = (float) userCpuMeter.getAvg(10); + alertCpu(cpu); + Mem m = sigar.getMem(); alertMem(m); From 6194d02660f17c9a8ec84746fec6e0e2838bd042 Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Wed, 24 Feb 2016 15:55:22 +0900 Subject: [PATCH 03/11] bug fix --- scouter.client/src/scouter/client/net/ClientTCP.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scouter.client/src/scouter/client/net/ClientTCP.java b/scouter.client/src/scouter/client/net/ClientTCP.java index e3bc7245f..20d470072 100644 --- a/scouter.client/src/scouter/client/net/ClientTCP.java +++ b/scouter.client/src/scouter/client/net/ClientTCP.java @@ -60,8 +60,8 @@ public void open(int serverId) { //*************// if (server.isConnected() == false) { System.out.println("Success to connect " + server.getIp() + ":" + server.getPort()); - server.setConnected(true); } + server.setConnected(true); } catch (Throwable t) { System.out.println(t.getMessage()); close(); From 1a7864dafc3634310b4c9aa38249ec8dac7a5290 Mon Sep 17 00:00:00 2001 From: Gunhee Lee Date: Thu, 25 Feb 2016 10:26:14 +0900 Subject: [PATCH 04/11] build name --- scouter.deploy/build-agent.host.xml | 2 +- scouter.deploy/build-agent.java.xml | 2 +- scouter.deploy/build-common.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scouter.deploy/build-agent.host.xml b/scouter.deploy/build-agent.host.xml index 18bca9d57..ce082f4ba 100644 --- a/scouter.deploy/build-agent.host.xml +++ b/scouter.deploy/build-agent.host.xml @@ -1,6 +1,6 @@ - + diff --git a/scouter.deploy/build-agent.java.xml b/scouter.deploy/build-agent.java.xml index 0eb313d04..0282e0e69 100644 --- a/scouter.deploy/build-agent.java.xml +++ b/scouter.deploy/build-agent.java.xml @@ -1,6 +1,6 @@ - + diff --git a/scouter.deploy/build-common.xml b/scouter.deploy/build-common.xml index 4654853de..c9b3e810c 100644 --- a/scouter.deploy/build-common.xml +++ b/scouter.deploy/build-common.xml @@ -1,6 +1,6 @@ - + From a0195ee925e20427924c5fe1e9b5b311e01eaf32 Mon Sep 17 00:00:00 2001 From: Gunhee Lee Date: Fri, 26 Feb 2016 12:21:05 +0900 Subject: [PATCH 05/11] commit, push test --- touchfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 touchfile diff --git a/touchfile b/touchfile new file mode 100644 index 000000000..e69de29bb From 41a6e2f9ed3b71464b61744f1aae45fed54f7259 Mon Sep 17 00:00:00 2001 From: "Paul S.J. Kim" Date: Fri, 26 Feb 2016 17:57:32 +0900 Subject: [PATCH 06/11] add options for boot class bci --- scouter.agent.java/src/scouter/agent/AgentTransformer.java | 6 ++++-- scouter.agent.java/src/scouter/agent/Configure.java | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scouter.agent.java/src/scouter/agent/AgentTransformer.java b/scouter.agent.java/src/scouter/agent/AgentTransformer.java index 19cdf3a8a..90fa42827 100644 --- a/scouter.agent.java/src/scouter/agent/AgentTransformer.java +++ b/scouter.agent.java/src/scouter/agent/AgentTransformer.java @@ -109,8 +109,10 @@ public byte[] transform(ClassLoader loader, String className, Class classBeingRe AsyncRunner.getInstance().add(loader, className, classfileBuffer); return null; } - if (loader == null) { - return null; + if (loader == null ) { + if(conf._hook_boot_prefix==null || conf._hook_boot_prefix.length()==0 || false == className.startsWith(conf._hook_boot_prefix)){ + return null; + } } } if (className.startsWith("scouter/")) { diff --git a/scouter.agent.java/src/scouter/agent/Configure.java b/scouter.agent.java/src/scouter/agent/Configure.java index c3d737185..2f82473e9 100644 --- a/scouter.agent.java/src/scouter/agent/Configure.java +++ b/scouter.agent.java/src/scouter/agent/Configure.java @@ -31,6 +31,7 @@ public class Configure extends Thread { public static boolean JDBC_REDEFINED = false; private static Configure instance = null; + public final static synchronized Configure getInstance() { if (instance == null) { instance = new Configure(); @@ -182,6 +183,7 @@ public final static synchronized Configure getInstance() { public boolean _hook_usertx_enabled = true; public String _hook_direct_patch_classes = ""; public boolean _hook_spring_rest_enabled = false; + public String _hook_boot_prefix=null; //Control public boolean control_reject_service_enabled = false; @@ -443,6 +445,7 @@ private void apply() { this.trace_db2_enabled = getBoolean("trace_db2_enabled", true); this._hook_usertx_enabled = getBoolean("_hook_usertx_enabled", true); this._hook_direct_patch_classes = getValue("_hook_direct_patch_classes", ""); + this._hook_boot_prefix = getValue("_hook_boot_prefix"); this.counter_recentuser_valid_ms = getLong("counter_recentuser_valid_ms", DateUtil.MILLIS_PER_FIVE_MINUTE); this.counter_object_registry_path = getValue("counter_object_registry_path", "/tmp/scouter"); this.sfa_dump_enabled = getBoolean("sfa_dump_enabled", false); From 0b010b572f0771accf749786fef1df3192ef696c Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Thu, 3 Mar 2016 15:47:41 +0900 Subject: [PATCH 07/11] add log --- scouter.server/src/scouter/server/core/AutoDeleteScheduler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scouter.server/src/scouter/server/core/AutoDeleteScheduler.java b/scouter.server/src/scouter/server/core/AutoDeleteScheduler.java index 24360edb2..260d7cf5c 100644 --- a/scouter.server/src/scouter/server/core/AutoDeleteScheduler.java +++ b/scouter.server/src/scouter/server/core/AutoDeleteScheduler.java @@ -119,7 +119,7 @@ private void deleteData(String yyyymmdd) { f = new File(dbDir, yyyymmdd); } deleteFiles(f); - Logger.println("S206", yyyymmdd); + Logger.println("S206", "Auto deletion... " + yyyymmdd); } catch (Throwable th) { Logger.println("S207", "Failed auto deletion... " + yyyymmdd + " " + th.toString()); } From b2cacb3693e2d7ffdfcf86e9adeb602fcf5ed51e Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Thu, 3 Mar 2016 18:14:47 +0900 Subject: [PATCH 08/11] separate service group view to throughput/elapsed --- scouter.client/plugin.xml | 56 +- .../OpenServiceGroupElapsedAction.java | 54 ++ .../OpenServiceGroupElapsedGroupAction.java | 49 + ...on.java => OpenServiceGroupTPSAction.java} | 106 +-- ...va => OpenServiceGroupTPSGroupAction.java} | 101 +- .../group/view/GroupNavigationView.java | 8 +- .../view/ServiceGroupElapsedGroupView.java | 123 +++ ...iew.java => ServiceGroupTPSGroupView.java} | 257 +++--- .../src/scouter/client/util/MenuUtil.java | 8 +- .../AbstractServiceGroupElapsedView.java | 327 +++++++ ....java => AbstractServiceGroupTPSView.java} | 869 +++++++----------- .../client/views/CounterStackCommonView.java | 2 +- .../client/views/ServiceGroupElapsedView.java | 86 ++ ...roupView.java => ServiceGroupTPSView.java} | 183 ++-- 14 files changed, 1346 insertions(+), 883 deletions(-) create mode 100644 scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedAction.java create mode 100644 scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedGroupAction.java rename scouter.client/src/scouter/client/actions/{OpenServiceGroupAction.java => OpenServiceGroupTPSAction.java} (68%) rename scouter.client/src/scouter/client/actions/{OpenServiceGroupGroupAction.java => OpenServiceGroupTPSGroupAction.java} (69%) create mode 100644 scouter.client/src/scouter/client/group/view/ServiceGroupElapsedGroupView.java rename scouter.client/src/scouter/client/group/view/{ServiceGroupGroupView.java => ServiceGroupTPSGroupView.java} (85%) create mode 100644 scouter.client/src/scouter/client/views/AbstractServiceGroupElapsedView.java rename scouter.client/src/scouter/client/views/{ServiceGroupCommonView.java => AbstractServiceGroupTPSView.java} (65%) create mode 100644 scouter.client/src/scouter/client/views/ServiceGroupElapsedView.java rename scouter.client/src/scouter/client/views/{ServiceGroupView.java => ServiceGroupTPSView.java} (82%) diff --git a/scouter.client/plugin.xml b/scouter.client/plugin.xml index 9e039bc0f..73818462c 100644 --- a/scouter.client/plugin.xml +++ b/scouter.client/plugin.xml @@ -455,14 +455,6 @@ name="Data File Management" restorable="false"> - - - - - - + + + + + + + + diff --git a/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedAction.java b/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedAction.java new file mode 100644 index 000000000..867398ad8 --- /dev/null +++ b/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedAction.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.Images; +import scouter.client.views.ServiceGroupElapsedView; +import scouter.lang.counters.CounterConstants; + +public class OpenServiceGroupElapsedAction extends Action { + public final static String ID = OpenServiceGroupElapsedAction.class.getName(); + + private final IWorkbenchWindow window; + int serverId; + String objType; + + public OpenServiceGroupElapsedAction(IWorkbenchWindow window, int serverId, String objType) { + this.window = window; + this.serverId = serverId; + this.objType = objType; + setText("Elapsed"); + setId(ID); + setImageDescriptor(Images.getCounterImageDescriptor(objType, CounterConstants.WAS_ELAPSED_TIME, serverId)); + } + + public void run() { + if (window != null) { + try { + window.getActivePage().showView(ServiceGroupElapsedView.ID, serverId + "&" + objType, IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + } +} diff --git a/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedGroupAction.java b/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedGroupAction.java new file mode 100644 index 000000000..97d242ec4 --- /dev/null +++ b/scouter.client/src/scouter/client/actions/OpenServiceGroupElapsedGroupAction.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.group.view.ServiceGroupElapsedGroupView; + +public class OpenServiceGroupElapsedGroupAction extends Action { + public final static String ID = OpenServiceGroupElapsedGroupAction.class.getName(); + + private final IWorkbenchWindow window; + String grpName; + + public OpenServiceGroupElapsedGroupAction(IWorkbenchWindow window, String grpName) { + this.window = window; + this.grpName = grpName; + setText("Elapsed"); + setId(ID); + } + + public void run() { + if (window != null) { + try { + window.getActivePage().showView(ServiceGroupElapsedGroupView.ID, grpName, IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + } +} diff --git a/scouter.client/src/scouter/client/actions/OpenServiceGroupAction.java b/scouter.client/src/scouter/client/actions/OpenServiceGroupTPSAction.java similarity index 68% rename from scouter.client/src/scouter/client/actions/OpenServiceGroupAction.java rename to scouter.client/src/scouter/client/actions/OpenServiceGroupTPSAction.java index 274a154b8..43a2c8628 100644 --- a/scouter.client/src/scouter/client/actions/OpenServiceGroupAction.java +++ b/scouter.client/src/scouter/client/actions/OpenServiceGroupTPSAction.java @@ -1,54 +1,54 @@ -/* +/* * Copyright 2015 the original author or authors. - * @https://github.com/scouter-project/scouter - * - * 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 scouter.client.actions; - -import org.eclipse.jface.action.Action; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; - -import scouter.client.Images; -import scouter.client.util.ImageUtil; -import scouter.client.views.ServiceGroupView; - -public class OpenServiceGroupAction extends Action { - public final static String ID = OpenServiceGroupAction.class.getName(); - - private final IWorkbenchWindow window; - int serverId; - String objType; - - public OpenServiceGroupAction(IWorkbenchWindow window, int serverId, String objType) { - this.window = window; - this.serverId = serverId; - this.objType = objType; - setText("Serivce Group"); - setId(ID); - setImageDescriptor(ImageUtil.getImageDescriptor(Images.sum)); - } - - public void run() { - if (window != null) { - try { - window.getActivePage().showView(ServiceGroupView.ID, serverId + "&" + objType, IWorkbenchPage.VIEW_ACTIVATE); - } catch (PartInitException e) { - e.printStackTrace(); - } - } - } -} + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.Images; +import scouter.client.views.ServiceGroupTPSView; +import scouter.lang.counters.CounterConstants; + +public class OpenServiceGroupTPSAction extends Action { + public final static String ID = OpenServiceGroupTPSAction.class.getName(); + + private final IWorkbenchWindow window; + int serverId; + String objType; + + public OpenServiceGroupTPSAction(IWorkbenchWindow window, int serverId, String objType) { + this.window = window; + this.serverId = serverId; + this.objType = objType; + setText("Throughput"); + setId(ID); + setImageDescriptor(Images.getCounterImageDescriptor(objType, CounterConstants.WAS_TPS, serverId)); + } + + public void run() { + if (window != null) { + try { + window.getActivePage().showView(ServiceGroupTPSView.ID, serverId + "&" + objType, IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + } +} diff --git a/scouter.client/src/scouter/client/actions/OpenServiceGroupGroupAction.java b/scouter.client/src/scouter/client/actions/OpenServiceGroupTPSGroupAction.java similarity index 69% rename from scouter.client/src/scouter/client/actions/OpenServiceGroupGroupAction.java rename to scouter.client/src/scouter/client/actions/OpenServiceGroupTPSGroupAction.java index 2b0317aea..ebde25a69 100644 --- a/scouter.client/src/scouter/client/actions/OpenServiceGroupGroupAction.java +++ b/scouter.client/src/scouter/client/actions/OpenServiceGroupTPSGroupAction.java @@ -1,52 +1,51 @@ -/* +/* * Copyright 2015 the original author or authors. - * @https://github.com/scouter-project/scouter - * - * 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 scouter.client.actions; - -import org.eclipse.jface.action.Action; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; - -import scouter.client.Images; -import scouter.client.group.view.ServiceGroupGroupView; -import scouter.client.util.ImageUtil; - -public class OpenServiceGroupGroupAction extends Action { - public final static String ID = OpenServiceGroupGroupAction.class.getName(); - - private final IWorkbenchWindow window; - String grpName; - - public OpenServiceGroupGroupAction(IWorkbenchWindow window, String grpName) { - this.window = window; - this.grpName = grpName; - setText("Service Group"); - setId(ID); - setImageDescriptor(ImageUtil.getImageDescriptor(Images.sum)); - } - - public void run() { - if (window != null) { - try { - window.getActivePage().showView(ServiceGroupGroupView.ID, grpName, IWorkbenchPage.VIEW_ACTIVATE); - } catch (PartInitException e) { - e.printStackTrace(); - } - } - } -} + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; + +import scouter.client.Images; +import scouter.client.group.view.ServiceGroupTPSGroupView; +import scouter.client.util.ImageUtil; + +public class OpenServiceGroupTPSGroupAction extends Action { + public final static String ID = OpenServiceGroupTPSGroupAction.class.getName(); + + private final IWorkbenchWindow window; + String grpName; + + public OpenServiceGroupTPSGroupAction(IWorkbenchWindow window, String grpName) { + this.window = window; + this.grpName = grpName; + setText("Throughput"); + setId(ID); + } + + public void run() { + if (window != null) { + try { + window.getActivePage().showView(ServiceGroupTPSGroupView.ID, grpName, IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException e) { + e.printStackTrace(); + } + } + } +} diff --git a/scouter.client/src/scouter/client/group/view/GroupNavigationView.java b/scouter.client/src/scouter/client/group/view/GroupNavigationView.java index a3015b199..f1d56fba9 100644 --- a/scouter.client/src/scouter/client/group/view/GroupNavigationView.java +++ b/scouter.client/src/scouter/client/group/view/GroupNavigationView.java @@ -59,7 +59,8 @@ import scouter.client.actions.OpenAddGroupAction; import scouter.client.actions.OpenEQGroupViewAction; import scouter.client.actions.OpenManageGroupAction; -import scouter.client.actions.OpenServiceGroupGroupAction; +import scouter.client.actions.OpenServiceGroupElapsedGroupAction; +import scouter.client.actions.OpenServiceGroupTPSGroupAction; import scouter.client.constants.MenuStr; import scouter.client.context.actions.OpenCxtmenuAssginGroupAction; import scouter.client.counter.actions.OpenActiveSpeedGroupViewAction; @@ -215,7 +216,10 @@ public void menuAboutToShow(IMenuManager manager){ manager.add(scMenu); scMenu.add(new OpenPastDateGroupCountViewAction(win, MenuStr.LOAD_SERVICE_COUNT, CounterConstants.WAS_SERVICE_COUNT, grpObj)); scMenu.add(new OpenTodayGroupCountViewAction(win, MenuStr.TODAY_SERVICE_COUNT, CounterConstants.WAS_SERVICE_COUNT, grpObj)); - manager.add(new OpenServiceGroupGroupAction(win, grpName)); + MenuManager serviceGroupMgr = new MenuManager("Serivce Group", ImageUtil.getImageDescriptor(Images.sum), "scouter.menu.id.group.javee.servicegroup"); + manager.add(serviceGroupMgr); + serviceGroupMgr.add(new OpenServiceGroupTPSGroupAction(win, grpName)); + serviceGroupMgr.add(new OpenServiceGroupElapsedGroupAction(win, grpName)); } } } else if (selObject instanceof AgentObject) { diff --git a/scouter.client/src/scouter/client/group/view/ServiceGroupElapsedGroupView.java b/scouter.client/src/scouter/client/group/view/ServiceGroupElapsedGroupView.java new file mode 100644 index 000000000..c9c293a0e --- /dev/null +++ b/scouter.client/src/scouter/client/group/view/ServiceGroupElapsedGroupView.java @@ -0,0 +1,123 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.group.view; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.net.TcpProxy; +import scouter.client.util.ScouterUtil; +import scouter.client.util.TimeUtil; +import scouter.client.views.AbstractServiceGroupElapsedView; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.net.RequestCmd; +import scouter.util.CastUtil; + +public class ServiceGroupElapsedGroupView extends AbstractServiceGroupElapsedView { + + public final static String ID = ServiceGroupElapsedGroupView.class.getName(); + + String grpName; + private Map serverObjMap = new HashMap(); + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + grpName = secId; + } + + public void createPartControl(Composite parent) { + this.setPartName("Service[Elapsed] - " + grpName); + super.createPartControl(parent); + } + + @Override + public MapPack fetch() { + ScouterUtil.collectGroupObjcts(grpName, serverObjMap); + HashMap valueMap = new HashMap(); + Iterator itr = serverObjMap.keySet().iterator(); + while (itr.hasNext()) { + int serverId = itr.next(); + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + try { + MapPack param = new MapPack(); + param.put("objHash", serverObjMap.get(serverId)); + MapPack p = (MapPack) tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); + if (p != null) { + ListValue nameLv = p.getList("name"); + ListValue countLv = p.getList("count"); + ListValue elapsedLv = p.getList("elapsed"); + ListValue errorLv = p.getList("error"); + for (int i = 0, max = (nameLv == null ? 0 : nameLv.size()) ; i < max; i++) { + String name = nameLv.getString(i); + PerfStat perf = valueMap.get(name); + if (perf == null) { + perf = new PerfStat(); + valueMap.put(name, perf); + } + perf.count += CastUtil.cint(countLv.get(i)); + perf.elapsed += CastUtil.clong(elapsedLv.get(i)); + perf.error += CastUtil.cint(errorLv.get(i)); + } + } + } catch (Throwable th) { + th.printStackTrace(); + } finally { + TcpProxy.putTcpProxy(tcp); + } + } + MapPack m = null; + if (valueMap.size() > 0) { + m = new MapPack(); + ListValue nameLv = m.newList("name"); + ListValue countLv = m.newList("count"); + ListValue elapsedLv = m.newList("elapsed"); + ListValue errorLv = m.newList("error"); + Iterator itrr = valueMap.keySet().iterator(); + while (itrr.hasNext()) { + String name = itrr.next(); + PerfStat perf = valueMap.get(name); + nameLv.add(name); + countLv.add(perf.count); + elapsedLv.add(perf.elapsed); + errorLv.add(perf.error); + } + long time = TimeUtil.getCurrentTime(); + m.put("time", time); + } + return m; + } + + public static class PerfStat { + public int count; + public int error; + public long elapsed; + + public void add(PerfStat o) { + this.count += o.count; + this.error += o.error; + this.elapsed += o.elapsed; + } + } +} diff --git a/scouter.client/src/scouter/client/group/view/ServiceGroupGroupView.java b/scouter.client/src/scouter/client/group/view/ServiceGroupTPSGroupView.java similarity index 85% rename from scouter.client/src/scouter/client/group/view/ServiceGroupGroupView.java rename to scouter.client/src/scouter/client/group/view/ServiceGroupTPSGroupView.java index 6fb1ce20b..3e96802db 100644 --- a/scouter.client/src/scouter/client/group/view/ServiceGroupGroupView.java +++ b/scouter.client/src/scouter/client/group/view/ServiceGroupTPSGroupView.java @@ -1,136 +1,123 @@ -/* +/* * Copyright 2015 the original author or authors. - * @https://github.com/scouter-project/scouter - * - * 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 scouter.client.group.view; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.IViewSite; -import org.eclipse.ui.PartInitException; - -import scouter.client.net.TcpProxy; -import scouter.client.util.TimeUtil; -import scouter.client.util.ScouterUtil; -import scouter.client.views.ServiceGroupCommonView; -import scouter.lang.pack.MapPack; -import scouter.lang.value.ListValue; -import scouter.net.RequestCmd; -import scouter.util.CastUtil; - -public class ServiceGroupGroupView extends ServiceGroupCommonView { - - public final static String ID = ServiceGroupGroupView.class.getName(); - - String grpName; - private Map serverObjMap = new HashMap(); - - public void init(IViewSite site) throws PartInitException { - super.init(site); - String secId = site.getSecondaryId(); - grpName = secId; - } - - public void createPartControl(Composite parent) { - this.setPartName("Service[Throughput] - " + grpName); - super.createPartControl(parent); - } - - @Override - public MapPack fetch() { - ScouterUtil.collectGroupObjcts(grpName, serverObjMap); - HashMap valueMap = new HashMap(); - Iterator itr = serverObjMap.keySet().iterator(); - while (itr.hasNext()) { - int serverId = itr.next(); - TcpProxy tcp = TcpProxy.getTcpProxy(serverId); - try { - MapPack param = new MapPack(); - param.put("objHash", serverObjMap.get(serverId)); - MapPack p = (MapPack) tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); - if (p != null) { - ListValue nameLv = p.getList("name"); - ListValue countLv = p.getList("count"); - ListValue elapsedLv = p.getList("elapsed"); - ListValue errorLv = p.getList("error"); - for (int i = 0, max = (nameLv == null ? 0 : nameLv.size()) ; i < max; i++) { - String name = nameLv.getString(i); - PerfStat perf = valueMap.get(name); - if (perf == null) { - perf = new PerfStat(); - valueMap.put(name, perf); - } - perf.count += CastUtil.cint(countLv.get(i)); - perf.elapsed += CastUtil.clong(elapsedLv.get(i)); - perf.error += CastUtil.cint(errorLv.get(i)); - } - } - } catch (Throwable th) { - th.printStackTrace(); - } finally { - TcpProxy.putTcpProxy(tcp); - } - } - MapPack m = null; - if (valueMap.size() > 0) { - m = new MapPack(); - ListValue nameLv = m.newList("name"); - ListValue countLv = m.newList("count"); - ListValue elapsedLv = m.newList("elapsed"); - ListValue errorLv = m.newList("error"); - Iterator itrr = valueMap.keySet().iterator(); - while (itrr.hasNext()) { - String name = itrr.next(); - PerfStat perf = valueMap.get(name); - nameLv.add(name); - countLv.add(perf.count); - elapsedLv.add(perf.elapsed); - errorLv.add(perf.error); - } - long time = TimeUtil.getCurrentTime(); - m.put("time", time); - fiveMinMap.put(time, m); - } - return m; - } - - public static class PerfStat { - public int count; - public int error; - public long elapsed; - - public void add(PerfStat o) { - this.count += o.count; - this.error += o.error; - this.elapsed += o.elapsed; - } - } - - @Override - public void setTitleName(MODE mode) { - switch (mode) { - case THROUGHPUT: - this.setPartName("Service[Throughput] - " + grpName); - break; - case ELASPED: - this.setPartName("Service[Elapsed Time] - " + grpName); - break; - } - } -} + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.group.view; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.net.TcpProxy; +import scouter.client.util.TimeUtil; +import scouter.client.util.ScouterUtil; +import scouter.client.views.AbstractServiceGroupTPSView; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.net.RequestCmd; +import scouter.util.CastUtil; + +public class ServiceGroupTPSGroupView extends AbstractServiceGroupTPSView { + + public final static String ID = ServiceGroupTPSGroupView.class.getName(); + + String grpName; + private Map serverObjMap = new HashMap(); + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + grpName = secId; + } + + public void createPartControl(Composite parent) { + this.setPartName("Service[Throughput] - " + grpName); + super.createPartControl(parent); + } + + @Override + public MapPack fetch() { + ScouterUtil.collectGroupObjcts(grpName, serverObjMap); + HashMap valueMap = new HashMap(); + Iterator itr = serverObjMap.keySet().iterator(); + while (itr.hasNext()) { + int serverId = itr.next(); + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + try { + MapPack param = new MapPack(); + param.put("objHash", serverObjMap.get(serverId)); + MapPack p = (MapPack) tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); + if (p != null) { + ListValue nameLv = p.getList("name"); + ListValue countLv = p.getList("count"); + ListValue elapsedLv = p.getList("elapsed"); + ListValue errorLv = p.getList("error"); + for (int i = 0, max = (nameLv == null ? 0 : nameLv.size()) ; i < max; i++) { + String name = nameLv.getString(i); + PerfStat perf = valueMap.get(name); + if (perf == null) { + perf = new PerfStat(); + valueMap.put(name, perf); + } + perf.count += CastUtil.cint(countLv.get(i)); + perf.elapsed += CastUtil.clong(elapsedLv.get(i)); + perf.error += CastUtil.cint(errorLv.get(i)); + } + } + } catch (Throwable th) { + th.printStackTrace(); + } finally { + TcpProxy.putTcpProxy(tcp); + } + } + MapPack m = null; + if (valueMap.size() > 0) { + m = new MapPack(); + ListValue nameLv = m.newList("name"); + ListValue countLv = m.newList("count"); + ListValue elapsedLv = m.newList("elapsed"); + ListValue errorLv = m.newList("error"); + Iterator itrr = valueMap.keySet().iterator(); + while (itrr.hasNext()) { + String name = itrr.next(); + PerfStat perf = valueMap.get(name); + nameLv.add(name); + countLv.add(perf.count); + elapsedLv.add(perf.elapsed); + errorLv.add(perf.error); + } + long time = TimeUtil.getCurrentTime(); + m.put("time", time); + } + return m; + } + + public static class PerfStat { + public int count; + public int error; + public long elapsed; + + public void add(PerfStat o) { + this.count += o.count; + this.error += o.error; + this.elapsed += o.elapsed; + } + } +} diff --git a/scouter.client/src/scouter/client/util/MenuUtil.java b/scouter.client/src/scouter/client/util/MenuUtil.java index 200278059..796696523 100644 --- a/scouter.client/src/scouter/client/util/MenuUtil.java +++ b/scouter.client/src/scouter/client/util/MenuUtil.java @@ -41,7 +41,8 @@ import scouter.client.actions.OpenActiveServiceListAction; import scouter.client.actions.OpenActiveSpeedAction; import scouter.client.actions.OpenEQViewAction; -import scouter.client.actions.OpenServiceGroupAction; +import scouter.client.actions.OpenServiceGroupElapsedAction; +import scouter.client.actions.OpenServiceGroupTPSAction; import scouter.client.actions.SetColorAction; import scouter.client.configuration.actions.DefineObjectTypeAction; import scouter.client.configuration.actions.OpenAgentConfigureAction; @@ -496,7 +497,10 @@ public static void addObjTypeSpecialMenu(IWorkbenchWindow win, IMenuManager mgr, mgr.add(new OpenActiveSpeedAction(win,objType, Images.TYPE_ACTSPEED, serverId)); mgr.add(new OpenXLogRealTimeAction(win, MenuStr.XLOG, objType, Images.star, serverId)); mgr.add(new OpenTodayServiceCountAction(win, MenuStr.SERVICE_COUNT, objType, CounterConstants.WAS_SERVICE_COUNT, Images.bar, serverId)); - mgr.add(new OpenServiceGroupAction(win, serverId, objType)); + MenuManager serviceGroupMgr = new MenuManager("Serivce Group", ImageUtil.getImageDescriptor(Images.sum), "scouter.menu.id.javee.servicegroup"); + mgr.add(serviceGroupMgr); + serviceGroupMgr.add(new OpenServiceGroupTPSAction(win, serverId, objType)); + serviceGroupMgr.add(new OpenServiceGroupElapsedAction(win, serverId, objType)); mgr.add(new OpenUniqueTotalVisitorAction(win, serverId, objType)); mgr.add(new OpenTypeSummaryAction(win, serverId, objType)); } diff --git a/scouter.client/src/scouter/client/views/AbstractServiceGroupElapsedView.java b/scouter.client/src/scouter/client/views/AbstractServiceGroupElapsedView.java new file mode 100644 index 000000000..1c4c658af --- /dev/null +++ b/scouter.client/src/scouter/client/views/AbstractServiceGroupElapsedView.java @@ -0,0 +1,327 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.views; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.csstudio.swt.xygraph.dataprovider.CircularBufferDataProvider; +import org.csstudio.swt.xygraph.dataprovider.ISample; +import org.csstudio.swt.xygraph.dataprovider.Sample; +import org.csstudio.swt.xygraph.figures.Trace; +import org.csstudio.swt.xygraph.figures.Trace.PointStyle; +import org.csstudio.swt.xygraph.figures.Trace.TraceType; +import org.csstudio.swt.xygraph.figures.XYGraph; +import org.csstudio.swt.xygraph.linearscale.Range; +import org.eclipse.draw2d.FigureCanvas; +import org.eclipse.jface.window.DefaultToolTip; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.part.ViewPart; + +import scouter.client.Images; +import scouter.client.listeners.RangeMouseListener; +import scouter.client.model.RefreshThread; +import scouter.client.model.RefreshThread.Refreshable; +import scouter.client.model.ServiceGroupColorManager; +import scouter.client.preferences.PManager; +import scouter.client.preferences.PreferenceConstants; +import scouter.client.util.ChartUtil; +import scouter.client.util.ColorUtil; +import scouter.client.util.ExUtil; +import scouter.client.util.ScouterUtil; +import scouter.client.util.TimeUtil; +import scouter.client.util.UIUtil; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.util.CastUtil; +import scouter.util.DateUtil; +import scouter.util.FormatUtil; + +public abstract class AbstractServiceGroupElapsedView extends ViewPart implements Refreshable { + + public final static String ID = AbstractServiceGroupElapsedView.class.getName(); + + private final static int BUFFER_SIZE = 200; + protected RefreshThread thread; + + protected XYGraph xyGraph; + protected FigureCanvas canvas; + + protected Map traces = new HashMap(); + Trace nearestTrace = null; + + private int manualRangeCount; + private double manualY; + + public void createPartControl(Composite parent) { + parent.setLayout(UIUtil.formLayout(0, 0)); + canvas = new FigureCanvas(parent); + canvas.setScrollBarVisibility(FigureCanvas.NEVER); + canvas.setLayoutData(UIUtil.formData(0, 0, 0, 0, 100, 0, 100, 0)); + canvas.setBackground(ColorUtil.getInstance().getColor(SWT.COLOR_WHITE)); + canvas.addControlListener(new ControlListener() { + boolean lock = false; + public void controlResized(ControlEvent e) { + org.eclipse.swt.graphics.Rectangle r = canvas.getClientArea(); + if (!lock) { + lock = true; + xyGraph.setSize(r.width, r.height); + lock = false; + } + } + public void controlMoved(ControlEvent e) { + } + }); + final DefaultToolTip toolTip = new DefaultToolTip(canvas, DefaultToolTip.RECREATE, true); + toolTip.setFont(new Font(null, "Arial", 10, SWT.BOLD)); + toolTip.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + canvas.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + if (nearestTrace != null) { + nearestTrace.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + nearestTrace = null; + } + toolTip.hide(); + } + + public void mouseDown(MouseEvent e) { + double x = xyGraph.primaryXAxis.getPositionValue(e.x, false); + double y = xyGraph.primaryYAxis.getPositionValue(e.y, false); + if (x < 0 || y < 0) { + return; + } + double minDistance = 30.0d; + long time = 0; + double value = 0; + for (Trace t : traces.values()) { + ISample s = ScouterUtil.getNearestPoint(t.getDataProvider(), x); + if (s != null) { + int x2 = xyGraph.primaryXAxis.getValuePosition(s.getXValue(), false); + int y2 = xyGraph.primaryYAxis.getValuePosition(s.getYValue(), false); + double distance = ScouterUtil.getPointDistance(e.x, e.y, x2, y2); + if (minDistance > distance) { + minDistance = distance; + nearestTrace = t; + time = (long) s.getXValue(); + value = s.getYValue(); + } + } + } + if (nearestTrace != null) { + int width = PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH); + nearestTrace.setLineWidth(width + 2); + toolTip.setText(nearestTrace.getName() + + "\nTime : " + DateUtil.format(time, "HH:mm:ss") + + "\nValue : " + FormatUtil.print(value, "#,###.##")); + toolTip.show(new Point(e.x, e.y)); + } + } + public void mouseDoubleClick(MouseEvent e) {} + }); + canvas.addKeyListener(new KeyListener() { + public void keyReleased(KeyEvent e) { + } + + public void keyPressed(KeyEvent e) { + switch (e.keyCode) { + case 16777217:// UP Key + double max = xyGraph.primaryYAxis.getRange().getUpper(); + if (max > 10000) { + manualY = max + 1000; + } else if (max > 1000) { + manualY = max + 100; + } else if (max > 100) { + manualY = max + 10; + } else if (max == 3) { + manualY = 5; + } else { + manualY = max + 5; + } + manualRangeCount = 5; + xyGraph.primaryYAxis.setRange(0, manualY); + break; + case 16777218: // DOWN Key + max = xyGraph.primaryYAxis.getRange().getUpper(); + if (max > 10000) { + manualY = max - 1000; + } else if (max > 1000) { + manualY =max - 100; + } else if (max > 100) { + manualY =max - 10; + } else { + manualY = (max - 5) > 3 ? max -5 : 3; + } + manualRangeCount = 5; + xyGraph.primaryYAxis.setRange(0, manualY); + break; + } + } + }); + xyGraph = new XYGraph(); + xyGraph.setShowLegend(true); + xyGraph.setShowTitle(false); + canvas.setContents(xyGraph); + xyGraph.primaryXAxis.setDateEnabled(true); + xyGraph.primaryXAxis.setShowMajorGrid(true); + xyGraph.primaryYAxis.setAutoScale(true); + xyGraph.primaryYAxis.setShowMajorGrid(true); + xyGraph.primaryXAxis.setTitle(""); + xyGraph.primaryYAxis.setTitle(""); + + xyGraph.primaryYAxis.addMouseListener(new RangeMouseListener(getViewSite().getShell(), xyGraph.primaryYAxis)); + thread = new RefreshThread(this, 2000); + thread.start(); + } + + public void setFocus() {} + + @Override + public void dispose() { + super.dispose(); + if (this.thread != null) { + this.thread.shutdown(); + } + } + + boolean stopRefresh = false; + + public void refresh() { + if (stopRefresh) { + return; + } + MapPack m = fetch(); + if (m == null) { + ExUtil.exec(canvas, new Runnable() { + public void run() { + setTitleImage(Images.inactive); + long now = TimeUtil.getCurrentTime(); + xyGraph.primaryXAxis.setRange(now - DateUtil.MILLIS_PER_FIVE_MINUTE, now + 1); + } + }); + return; + } + removeDeadGroup(m); + processElapsedData(m); + } + + public abstract MapPack fetch(); + + private void removeDeadGroup(MapPack m) { + ListValue nameLv = m.getList("name"); + + ArrayList grpSet = new ArrayList(); + Iterator enu = traces.keySet().iterator(); + while(enu.hasNext()){ + grpSet.add(enu.next()); + } + for (int i = 0; i < nameLv.size(); i++) { + String name = nameLv.getString(i); + grpSet.remove(name); + } + for (String dead : grpSet) { + final Trace t = traces.get(dead); + if (t == null) continue; + ExUtil.exec(canvas, new Runnable() { + public void run() { + xyGraph.removeTrace(t); + } + }); + traces.remove(dead); + } + } + + private void processElapsedData(final MapPack m) { + final ListValue nameLv = m.getList("name"); + final ListValue elapsedLv = m.getList("elapsed"); + ExUtil.exec(canvas, new Runnable() { + public void run() { + setTitleImage(Images.active); + long now = m.getLong("time"); + long stime = now - DateUtil.MILLIS_PER_FIVE_MINUTE; + xyGraph.primaryXAxis.setRange(stime, now + 1); + for (int i = 0; i < nameLv.size(); i++) { + String name = nameLv.getString(i); + double value = CastUtil.cdouble(elapsedLv.get(i)) / 30.0d; + CircularBufferDataProvider provider = (CircularBufferDataProvider) getTrace(name).getDataProvider(); + provider.addSample(new Sample(now, value)); + } + xyGraph.primaryYAxis.setRange(0, getMaxValue()); + } + }); + } + + private Trace getTrace(String name) { + Trace trace = traces.get(name); + if (trace == null) { + CircularBufferDataProvider provider = new CircularBufferDataProvider(true); + provider.setBufferSize(BUFFER_SIZE); + trace = new Trace(name, xyGraph.primaryXAxis, xyGraph.primaryYAxis, provider); + trace.setPointStyle(PointStyle.NONE); + trace.getXAxis().setFormatPattern("HH:mm:ss"); + trace.getYAxis().setFormatPattern("#,##0"); + trace.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); + trace.setTraceType(TraceType.SOLID_LINE); + trace.setTraceColor(ServiceGroupColorManager.getInstance().assignColor(name)); + xyGraph.addTrace(trace); + traces.put(name, trace); + } + return trace; + } + + private double getMaxValue() { + Range xRange = xyGraph.primaryXAxis.getRange(); + double lower = xRange.getLower(); + double upper = xRange.getUpper(); + if (manualRangeCount > 0 && manualY > 0) { + manualRangeCount--; + return manualY; + } + double max = 0.0; + Iterator itr = traces.keySet().iterator(); + while (itr.hasNext()) { + String name = itr.next(); + CircularBufferDataProvider data = (CircularBufferDataProvider) traces.get(name).getDataProvider(); + if (data != null) { + for (int inx = 0; inx < data.getSize(); inx++) { + Sample sample = (Sample) data.getSample(inx); + double x = sample.getXValue(); + if(x < lower || x > upper) { + continue; + } + double y = sample.getYValue(); + if (y > max) { + max = y; + } + } + } + } + return ChartUtil.getGroupMaxValue(max); + } +} diff --git a/scouter.client/src/scouter/client/views/ServiceGroupCommonView.java b/scouter.client/src/scouter/client/views/AbstractServiceGroupTPSView.java similarity index 65% rename from scouter.client/src/scouter/client/views/ServiceGroupCommonView.java rename to scouter.client/src/scouter/client/views/AbstractServiceGroupTPSView.java index e1620abe9..fa33b433e 100644 --- a/scouter.client/src/scouter/client/views/ServiceGroupCommonView.java +++ b/scouter.client/src/scouter/client/views/AbstractServiceGroupTPSView.java @@ -1,518 +1,353 @@ -/* +/* * Copyright 2015 the original author or authors. - * @https://github.com/scouter-project/scouter - * - * 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 scouter.client.views; - -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.csstudio.swt.xygraph.dataprovider.CircularBufferDataProvider; -import org.csstudio.swt.xygraph.dataprovider.Sample; -import org.csstudio.swt.xygraph.figures.Trace; -import org.csstudio.swt.xygraph.figures.Trace.PointStyle; -import org.csstudio.swt.xygraph.figures.Trace.TraceType; -import org.csstudio.swt.xygraph.figures.XYGraph; -import org.csstudio.swt.xygraph.linearscale.Range; -import org.eclipse.draw2d.FigureCanvas; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.window.DefaultToolTip; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.part.ViewPart; - -import scouter.client.Activator; -import scouter.client.Images; -import scouter.client.model.RefreshThread; -import scouter.client.model.ServiceGroupColorManager; -import scouter.client.model.RefreshThread.Refreshable; -import scouter.client.preferences.PManager; -import scouter.client.preferences.PreferenceConstants; -import scouter.client.util.ChartUtil; -import scouter.client.util.ColorUtil; -import scouter.client.util.ExUtil; -import scouter.client.util.MenuUtil; -import scouter.client.util.TimeUtil; -import scouter.client.util.UIUtil; -import scouter.lang.pack.MapPack; -import scouter.lang.value.ListValue; -import scouter.util.CastUtil; -import scouter.util.DateUtil; -import scouter.util.LinkedMap; -import scouter.util.LongEnumer; -import scouter.util.LongKeyLinkedMap; - -public abstract class ServiceGroupCommonView extends ViewPart implements Refreshable { - - public final static String ID = ServiceGroupCommonView.class.getName(); - - private final static int BUFFER_SIZE = 200; - protected RefreshThread thread; - - protected XYGraph xyGraph; - protected FigureCanvas canvas; - - public MODE mode = MODE.THROUGHPUT; - - protected Map traces = new HashMap(); - protected LongKeyLinkedMap< MapPack> fiveMinMap = new LongKeyLinkedMap< MapPack>().setMax(BUFFER_SIZE); - private LinkedMap stackValueMap = new LinkedMap(); - - private int manualRangeCount; - private double manualY; - - public void createPartControl(Composite parent) { - parent.setLayout(UIUtil.formLayout(0, 0)); - canvas = new FigureCanvas(parent); - canvas.setScrollBarVisibility(FigureCanvas.NEVER); - canvas.setLayoutData(UIUtil.formData(0, 0, 0, 0, 100, 0, 100, 0)); - canvas.setBackground(ColorUtil.getInstance().getColor(SWT.COLOR_WHITE)); - canvas.addControlListener(new ControlListener() { - boolean lock = false; - public void controlResized(ControlEvent e) { - org.eclipse.swt.graphics.Rectangle r = canvas.getClientArea(); - if (!lock) { - lock = true; - xyGraph.setSize(r.width, r.height); - lock = false; - } - } - public void controlMoved(ControlEvent e) { - } - }); - final DefaultToolTip toolTip = new DefaultToolTip(canvas, DefaultToolTip.RECREATE, true); - toolTip.setFont(new Font(null, "Arial", 10, SWT.BOLD)); - toolTip.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); - canvas.addMouseListener(new MouseListener() { - - String selectedName; - - public void mouseUp(MouseEvent e) { - if (selectedName == null) { - return; - } - Trace trace = traces.get(selectedName); - trace.setTraceColor(ServiceGroupColorManager.getInstance().assignColor(selectedName)); - toolTip.hide(); - selectedName = null; - } - public void mouseDown(MouseEvent e) { - Image image = new Image(e.display, 1, 1); - GC gc = new GC((FigureCanvas)e.widget); - gc.copyArea(image, e.x, e.y); - ImageData imageData = image.getImageData(); - PaletteData palette = imageData.palette; - int pixelValue = imageData.getPixel(0, 0); - RGB rgb = palette.getRGB(pixelValue); - selectedName = ServiceGroupColorManager.getInstance().getServiceGroup(rgb); - if (selectedName != null) { - Trace trace = traces.get(selectedName); - trace.setTraceColor(ColorUtil.getInstance().getColor("dark magenta")); - toolTip.setText(selectedName); - toolTip.show(new Point(e.x, e.y)); - } - gc.dispose(); - image.dispose(); - } - public void mouseDoubleClick(MouseEvent e) {} - }); - canvas.addKeyListener(new KeyListener() { - public void keyReleased(KeyEvent e) { - } - - public void keyPressed(KeyEvent e) { - switch (e.keyCode) { - case 16777217:// UP Key - double max = xyGraph.primaryYAxis.getRange().getUpper(); - if (max > 10000) { - manualY = max + 1000; - } else if (max > 1000) { - manualY = max + 100; - } else if (max > 100) { - manualY = max + 10; - } else if (max == 3) { - manualY = 5; - } else { - manualY = max + 5; - } - manualRangeCount = 5; - xyGraph.primaryYAxis.setRange(0, manualY); - break; - case 16777218: // DOWN Key - max = xyGraph.primaryYAxis.getRange().getUpper(); - if (max > 10000) { - manualY = max - 1000; - } else if (max > 1000) { - manualY =max - 100; - } else if (max > 100) { - manualY =max - 10; - } else { - manualY = (max - 5) > 3 ? max -5 : 3; - } - manualRangeCount = 5; - xyGraph.primaryYAxis.setRange(0, manualY); - break; - } - } - }); - IToolBarManager man = getViewSite().getActionBars().getToolBarManager(); - ArrayList menus = new ArrayList(); - menus.add(new ChangeThroughput()); - menus.add(new ChangeElasped()); - MenuUtil.createMenu(getSite().getWorkbenchWindow(), man, menus, Images.arrow_rotate); - xyGraph = new XYGraph(); - xyGraph.setShowLegend(true); - xyGraph.setShowTitle(false); - canvas.setContents(xyGraph); - xyGraph.primaryXAxis.setDateEnabled(true); - xyGraph.primaryXAxis.setShowMajorGrid(true); - xyGraph.primaryYAxis.setAutoScale(true); - xyGraph.primaryYAxis.setShowMajorGrid(true); - xyGraph.primaryXAxis.setTitle(""); - xyGraph.primaryYAxis.setTitle(""); - thread = new RefreshThread(this, 2000); - thread.start(); - } - - public void setFocus() {} - - @Override - public void dispose() { - super.dispose(); - if (this.thread != null) { - this.thread.shutdown(); - } - } - - private void changeMode(MODE mode) { - if (this.mode == mode) { - return; - } - for (Trace trace : traces.values()) { - xyGraph.removeTrace(trace); - } - traces.clear(); - manualRangeCount = 0; - this.mode = mode; - setTitleName(mode); - try { - stopRefresh = true; - applyPrevData(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - stopRefresh = false; - } - } - - boolean stopRefresh = false; - - private void applyPrevData() { - final LinkedMap> tempMap = new LinkedMap>(); - LongEnumer keys = fiveMinMap.keys(); - while (keys.hasMoreElements()) { - long time = keys.nextLong(); - MapPack m = fiveMinMap.get(time); - ListValue nameLv = m.getList("name"); - ListValue countLv = m.getList("count"); - ListValue elapsedLv = m.getList("elapsed"); - switch (mode) { - case THROUGHPUT : - for (int i = 0; i < nameLv.size(); i++) { - String name = nameLv.getString(i); - double count = CastUtil.cdouble(countLv.get(i)) / 30.0d; - StackValue sv = stackValueMap.get(name); - if (sv == null) { - continue; - } - sv.actualValue = count; - sv.lastUpdateTime = time; - } - Enumeration itr = stackValueMap.keys(); - double stackValue = 0.0; - while (itr.hasMoreElements()) { - String name = itr.nextElement(); - StackValue sv = stackValueMap.get(name); - if (sv != null) { - if (tempMap.containsKey(name) == false) { - tempMap.putFirst(name, new ArrayList()); - } - if (sv.lastUpdateTime == time) { - stackValue += sv.actualValue; - List list = tempMap.get(name); - list.add(new Sample(time, stackValue)); - } - } - } - break; - case ELASPED: - for (int i = 0; i < nameLv.size(); i++) { - String name = nameLv.getString(i); - if (stackValueMap.containsKey(name) == false) { - continue; - } - double value = CastUtil.cdouble(elapsedLv.get(i)) / 30.0d; - List list = tempMap.get(name); - if (list == null) { - list = new ArrayList(); - tempMap.put(name, list); - } - list.add(new Sample(time, value)); - } - break; - } - } - - ExUtil.exec(canvas, new Runnable() { - public void run() { - Enumeration itr = tempMap.keys(); - while (itr.hasMoreElements()) { - String name = itr.nextElement(); - List list = tempMap.get(name); - CircularBufferDataProvider provider = (CircularBufferDataProvider) getTrace(name).getDataProvider(); - for (int i = 0; i < list.size(); i++) { - provider.addSample(list.get(i)); - } - } - } - }); - } - - public void refresh() { - if (stopRefresh) { - return; - } - MapPack m = fetch(); - if (m == null) { - ExUtil.exec(canvas, new Runnable() { - public void run() { - setTitleImage(Images.inactive); - long now = TimeUtil.getCurrentTime(); - xyGraph.primaryXAxis.setRange(now - DateUtil.MILLIS_PER_FIVE_MINUTE, now + 1); - } - }); - return; - } - removeDeadGroup(m); - switch (mode) { - case THROUGHPUT : - processThroughputData(m); - break; - case ELASPED: - processElapsedData(m); - break; - } - } - - public abstract void setTitleName(MODE mode); - public abstract MapPack fetch(); - - private void removeDeadGroup(MapPack m) { - ListValue nameLv = m.getList("name"); - - ArrayList grpSet = new ArrayList(); - Enumeration enu =stackValueMap.keys(); - while(enu.hasMoreElements()){ - grpSet.add(enu.nextElement()); - } - for (int i = 0; i < nameLv.size(); i++) { - String name = nameLv.getString(i); - grpSet.remove(name); - } - for (String dead : grpSet) { - stackValueMap.remove(dead); - final Trace t = traces.get(dead); - if (t == null) continue; - ExUtil.exec(canvas, new Runnable() { - public void run() { - xyGraph.removeTrace(t); - } - }); - traces.remove(dead); - } - } - - private void processThroughputData(MapPack m) { - ListValue nameLv = m.getList("name"); - ListValue countLv = m.getList("count"); - final long now = m.getLong("time"); - final long stime = now - DateUtil.MILLIS_PER_FIVE_MINUTE; - for (int i = 0; i < nameLv.size(); i++) { - String name = nameLv.getString(i); - double value = CastUtil.cdouble(countLv.get(i)) / 30.0d; - if (stackValueMap.containsKey(name)) { - StackValue sv = stackValueMap.get(name); - sv.actualValue = value; - sv.lastUpdateTime = now; - } else { - StackValue sv = new StackValue(); - sv.actualValue = value; - sv.lastUpdateTime = now; - stackValueMap.putFirst(name, sv); - } - } - Enumeration itr = stackValueMap.keys(); - final LinkedMap tempMap = new LinkedMap(); - double stackValue = 0.0; - while (itr.hasMoreElements()) { - String name = itr.nextElement(); - StackValue sv = stackValueMap.get(name); - if (sv.lastUpdateTime == now) { - stackValue += sv.actualValue; - sv.stackedValue = stackValue; - tempMap.putFirst(name, sv); - } - } - ExUtil.exec(canvas, new Runnable() { - public void run() { - setTitleImage(Images.active); - xyGraph.primaryXAxis.setRange(stime, now + 1); - Enumeration itr = tempMap.keys(); - while (itr.hasMoreElements()) { - String name = itr.nextElement(); - StackValue sv = tempMap.get(name); - CircularBufferDataProvider provider = (CircularBufferDataProvider) getTrace(name).getDataProvider(); - provider.addSample(new Sample(now, sv.stackedValue)); - } - xyGraph.primaryYAxis.setRange(0, getMaxValue()); - } - }); - } - - private void processElapsedData(final MapPack m) { - final ListValue nameLv = m.getList("name"); - final ListValue elapsedLv = m.getList("elapsed"); - ExUtil.exec(canvas, new Runnable() { - public void run() { - setTitleImage(Images.active); - long now = m.getLong("time"); - long stime = now - DateUtil.MILLIS_PER_FIVE_MINUTE; - xyGraph.primaryXAxis.setRange(stime, now + 1); - for (int i = 0; i < nameLv.size(); i++) { - String name = nameLv.getString(i); - double value = CastUtil.cdouble(elapsedLv.get(i)) / 30.0d; - CircularBufferDataProvider provider = (CircularBufferDataProvider) getTrace(name).getDataProvider(); - provider.addSample(new Sample(now, value)); - } - xyGraph.primaryYAxis.setRange(0, getMaxValue()); - } - }); - } - - private Trace getTrace(String name) { - Trace trace = traces.get(name); - if (trace == null) { - CircularBufferDataProvider provider = new CircularBufferDataProvider(true); - provider.setBufferSize(BUFFER_SIZE); - trace = new Trace(name, xyGraph.primaryXAxis, xyGraph.primaryYAxis, provider); - trace.setPointStyle(PointStyle.NONE); - trace.getXAxis().setFormatPattern("HH:mm:ss"); - trace.getYAxis().setFormatPattern("#,##0"); - if (this.mode == MODE.ELASPED) { - trace.setLineWidth(PManager.getInstance().getInt(PreferenceConstants.P_CHART_LINE_WIDTH)); - trace.setTraceType(TraceType.SOLID_LINE); - } else if (this.mode == MODE.THROUGHPUT) { - trace.setTraceType(TraceType.AREA); - trace.setAreaAlpha(255); - } - trace.setTraceColor(ServiceGroupColorManager.getInstance().assignColor(name)); - xyGraph.addTrace(trace); - traces.put(name, trace); - } - return trace; - } - - private double getMaxValue() { - Range xRange = xyGraph.primaryXAxis.getRange(); - double lower = xRange.getLower(); - double upper = xRange.getUpper(); - if (manualRangeCount > 0 && manualY > 0) { - manualRangeCount--; - return manualY; - } - double max = 0.0; - Iterator itr = traces.keySet().iterator(); - while (itr.hasNext()) { - String name = itr.next(); - CircularBufferDataProvider data = (CircularBufferDataProvider) traces.get(name).getDataProvider(); - if (data != null) { - for (int inx = 0; inx < data.getSize(); inx++) { - Sample sample = (Sample) data.getSample(inx); - double x = sample.getXValue(); - if(x < lower || x > upper) { - continue; - } - double y = sample.getYValue(); - if (y > max) { - max = y; - } - } - } - } - return ChartUtil.getGroupMaxValue(max); - } - - static class StackValue { - double actualValue; - double stackedValue; - long lastUpdateTime; - } - - public enum MODE { - THROUGHPUT, - ELASPED - } - - class ChangeThroughput extends Action { - ChangeThroughput () { - setText("Throughput"); - setImageDescriptor(Activator.getImageDescriptor("/icons/counter/transaction.png")); - } - - public void run() { - changeMode(MODE.THROUGHPUT); - } - } - - class ChangeElasped extends Action { - ChangeElasped () { - setText("Elapsed Time"); - setImageDescriptor(Activator.getImageDescriptor("/icons/counter/time.png")); - } - public void run() { - changeMode(MODE.ELASPED); - } - } -} + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.views; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.csstudio.swt.xygraph.dataprovider.CircularBufferDataProvider; +import org.csstudio.swt.xygraph.dataprovider.Sample; +import org.csstudio.swt.xygraph.figures.Trace; +import org.csstudio.swt.xygraph.figures.Trace.PointStyle; +import org.csstudio.swt.xygraph.figures.Trace.TraceType; +import org.csstudio.swt.xygraph.figures.XYGraph; +import org.csstudio.swt.xygraph.linearscale.Range; +import org.eclipse.draw2d.FigureCanvas; +import org.eclipse.jface.window.DefaultToolTip; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.part.ViewPart; + +import scouter.client.Images; +import scouter.client.listeners.RangeMouseListener; +import scouter.client.model.RefreshThread; +import scouter.client.model.RefreshThread.Refreshable; +import scouter.client.model.ServiceGroupColorManager; +import scouter.client.util.ChartUtil; +import scouter.client.util.ColorUtil; +import scouter.client.util.ExUtil; +import scouter.client.util.TimeUtil; +import scouter.client.util.UIUtil; +import scouter.lang.pack.MapPack; +import scouter.lang.value.ListValue; +import scouter.util.CastUtil; +import scouter.util.DateUtil; +import scouter.util.LinkedMap; + +public abstract class AbstractServiceGroupTPSView extends ViewPart implements Refreshable { + + public final static String ID = AbstractServiceGroupTPSView.class.getName(); + + private final static int BUFFER_SIZE = 200; + protected RefreshThread thread; + + protected XYGraph xyGraph; + protected FigureCanvas canvas; + + protected Map traces = new HashMap(); + private LinkedMap stackValueMap = new LinkedMap(); + + private int manualRangeCount; + private double manualY; + + public void createPartControl(Composite parent) { + parent.setLayout(UIUtil.formLayout(0, 0)); + canvas = new FigureCanvas(parent); + canvas.setScrollBarVisibility(FigureCanvas.NEVER); + canvas.setLayoutData(UIUtil.formData(0, 0, 0, 0, 100, 0, 100, 0)); + canvas.setBackground(ColorUtil.getInstance().getColor(SWT.COLOR_WHITE)); + canvas.addControlListener(new ControlListener() { + boolean lock = false; + public void controlResized(ControlEvent e) { + org.eclipse.swt.graphics.Rectangle r = canvas.getClientArea(); + if (!lock) { + lock = true; + xyGraph.setSize(r.width, r.height); + lock = false; + } + } + public void controlMoved(ControlEvent e) { + } + }); + final DefaultToolTip toolTip = new DefaultToolTip(canvas, DefaultToolTip.RECREATE, true); + toolTip.setFont(new Font(null, "Arial", 10, SWT.BOLD)); + toolTip.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + canvas.addMouseListener(new MouseListener() { + + String selectedName; + + public void mouseUp(MouseEvent e) { + if (selectedName == null) { + return; + } + Trace trace = traces.get(selectedName); + trace.setTraceColor(ServiceGroupColorManager.getInstance().assignColor(selectedName)); + toolTip.hide(); + selectedName = null; + } + public void mouseDown(MouseEvent e) { + Image image = new Image(e.display, 1, 1); + GC gc = new GC((FigureCanvas)e.widget); + gc.copyArea(image, e.x, e.y); + ImageData imageData = image.getImageData(); + PaletteData palette = imageData.palette; + int pixelValue = imageData.getPixel(0, 0); + RGB rgb = palette.getRGB(pixelValue); + selectedName = ServiceGroupColorManager.getInstance().getServiceGroup(rgb); + if (selectedName != null) { + Trace trace = traces.get(selectedName); + trace.setTraceColor(ColorUtil.getInstance().getColor("dark magenta")); + toolTip.setText(selectedName); + toolTip.show(new Point(e.x, e.y)); + } + gc.dispose(); + image.dispose(); + } + public void mouseDoubleClick(MouseEvent e) {} + }); + canvas.addKeyListener(new KeyListener() { + public void keyReleased(KeyEvent e) { + } + + public void keyPressed(KeyEvent e) { + switch (e.keyCode) { + case 16777217:// UP Key + double max = xyGraph.primaryYAxis.getRange().getUpper(); + if (max > 10000) { + manualY = max + 1000; + } else if (max > 1000) { + manualY = max + 100; + } else if (max > 100) { + manualY = max + 10; + } else if (max == 3) { + manualY = 5; + } else { + manualY = max + 5; + } + manualRangeCount = 5; + xyGraph.primaryYAxis.setRange(0, manualY); + break; + case 16777218: // DOWN Key + max = xyGraph.primaryYAxis.getRange().getUpper(); + if (max > 10000) { + manualY = max - 1000; + } else if (max > 1000) { + manualY =max - 100; + } else if (max > 100) { + manualY =max - 10; + } else { + manualY = (max - 5) > 3 ? max -5 : 3; + } + manualRangeCount = 5; + xyGraph.primaryYAxis.setRange(0, manualY); + break; + } + } + }); + xyGraph = new XYGraph(); + xyGraph.setShowLegend(true); + xyGraph.setShowTitle(false); + canvas.setContents(xyGraph); + xyGraph.primaryXAxis.setDateEnabled(true); + xyGraph.primaryXAxis.setShowMajorGrid(true); + xyGraph.primaryYAxis.setAutoScale(true); + xyGraph.primaryYAxis.setShowMajorGrid(true); + xyGraph.primaryXAxis.setTitle(""); + xyGraph.primaryYAxis.setTitle(""); + + xyGraph.primaryYAxis.addMouseListener(new RangeMouseListener(getViewSite().getShell(), xyGraph.primaryYAxis)); + thread = new RefreshThread(this, 2000); + thread.start(); + } + + public void setFocus() {} + + @Override + public void dispose() { + super.dispose(); + if (this.thread != null) { + this.thread.shutdown(); + } + } + + boolean stopRefresh = false; + + public void refresh() { + if (stopRefresh) { + return; + } + MapPack m = fetch(); + if (m == null) { + ExUtil.exec(canvas, new Runnable() { + public void run() { + setTitleImage(Images.inactive); + long now = TimeUtil.getCurrentTime(); + xyGraph.primaryXAxis.setRange(now - DateUtil.MILLIS_PER_FIVE_MINUTE, now + 1); + } + }); + return; + } + removeDeadGroup(m); + processThroughputData(m); + } + + public abstract MapPack fetch(); + + private void removeDeadGroup(MapPack m) { + ListValue nameLv = m.getList("name"); + + ArrayList grpSet = new ArrayList(); + Enumeration enu =stackValueMap.keys(); + while(enu.hasMoreElements()){ + grpSet.add(enu.nextElement()); + } + for (int i = 0; i < nameLv.size(); i++) { + String name = nameLv.getString(i); + grpSet.remove(name); + } + for (String dead : grpSet) { + stackValueMap.remove(dead); + final Trace t = traces.get(dead); + if (t == null) continue; + ExUtil.exec(canvas, new Runnable() { + public void run() { + xyGraph.removeTrace(t); + } + }); + traces.remove(dead); + } + } + + private void processThroughputData(MapPack m) { + ListValue nameLv = m.getList("name"); + ListValue countLv = m.getList("count"); + final long now = m.getLong("time"); + final long stime = now - DateUtil.MILLIS_PER_FIVE_MINUTE; + for (int i = 0; i < nameLv.size(); i++) { + String name = nameLv.getString(i); + double value = CastUtil.cdouble(countLv.get(i)) / 30.0d; + if (stackValueMap.containsKey(name)) { + StackValue sv = stackValueMap.get(name); + sv.actualValue = value; + sv.lastUpdateTime = now; + } else { + StackValue sv = new StackValue(); + sv.actualValue = value; + sv.lastUpdateTime = now; + stackValueMap.putFirst(name, sv); + } + } + Enumeration itr = stackValueMap.keys(); + final LinkedMap tempMap = new LinkedMap(); + double stackValue = 0.0; + while (itr.hasMoreElements()) { + String name = itr.nextElement(); + StackValue sv = stackValueMap.get(name); + if (sv.lastUpdateTime == now) { + stackValue += sv.actualValue; + sv.stackedValue = stackValue; + tempMap.putFirst(name, sv); + } + } + ExUtil.exec(canvas, new Runnable() { + public void run() { + setTitleImage(Images.active); + xyGraph.primaryXAxis.setRange(stime, now + 1); + Enumeration itr = tempMap.keys(); + while (itr.hasMoreElements()) { + String name = itr.nextElement(); + StackValue sv = tempMap.get(name); + CircularBufferDataProvider provider = (CircularBufferDataProvider) getTrace(name).getDataProvider(); + provider.addSample(new Sample(now, sv.stackedValue)); + } + xyGraph.primaryYAxis.setRange(0, getMaxValue()); + } + }); + } + + private Trace getTrace(String name) { + Trace trace = traces.get(name); + if (trace == null) { + CircularBufferDataProvider provider = new CircularBufferDataProvider(true); + provider.setBufferSize(BUFFER_SIZE); + trace = new Trace(name, xyGraph.primaryXAxis, xyGraph.primaryYAxis, provider); + trace.setPointStyle(PointStyle.NONE); + trace.getXAxis().setFormatPattern("HH:mm:ss"); + trace.getYAxis().setFormatPattern("#,##0"); + trace.setTraceType(TraceType.AREA); + trace.setAreaAlpha(255); + trace.setTraceColor(ServiceGroupColorManager.getInstance().assignColor(name)); + xyGraph.addTrace(trace); + traces.put(name, trace); + } + return trace; + } + + private double getMaxValue() { + Range xRange = xyGraph.primaryXAxis.getRange(); + double lower = xRange.getLower(); + double upper = xRange.getUpper(); + if (manualRangeCount > 0 && manualY > 0) { + manualRangeCount--; + return manualY; + } + double max = 0.0; + Iterator itr = traces.keySet().iterator(); + while (itr.hasNext()) { + String name = itr.next(); + CircularBufferDataProvider data = (CircularBufferDataProvider) traces.get(name).getDataProvider(); + if (data != null) { + for (int inx = 0; inx < data.getSize(); inx++) { + Sample sample = (Sample) data.getSample(inx); + double x = sample.getXValue(); + if(x < lower || x > upper) { + continue; + } + double y = sample.getYValue(); + if (y > max) { + max = y; + } + } + } + } + return ChartUtil.getGroupMaxValue(max); + } + + static class StackValue { + double actualValue; + double stackedValue; + long lastUpdateTime; + } +} diff --git a/scouter.client/src/scouter/client/views/CounterStackCommonView.java b/scouter.client/src/scouter/client/views/CounterStackCommonView.java index beca1059f..57a0e421b 100644 --- a/scouter.client/src/scouter/client/views/CounterStackCommonView.java +++ b/scouter.client/src/scouter/client/views/CounterStackCommonView.java @@ -56,7 +56,7 @@ import scouter.client.util.ExUtil; import scouter.client.util.TimeUtil; import scouter.client.util.UIUtil; -import scouter.client.views.ServiceGroupCommonView.StackValue; +import scouter.client.views.AbstractServiceGroupTPSView.StackValue; import scouter.lang.value.MapValue; import scouter.util.CastUtil; import scouter.util.DateUtil; diff --git a/scouter.client/src/scouter/client/views/ServiceGroupElapsedView.java b/scouter.client/src/scouter/client/views/ServiceGroupElapsedView.java new file mode 100644 index 000000000..a93b3a0c7 --- /dev/null +++ b/scouter.client/src/scouter/client/views/ServiceGroupElapsedView.java @@ -0,0 +1,86 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.views; + +import java.util.Map; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.model.AgentModelThread; +import scouter.client.model.AgentObject; +import scouter.client.net.TcpProxy; +import scouter.client.server.Server; +import scouter.client.server.ServerManager; +import scouter.client.util.TimeUtil; +import scouter.lang.pack.MapPack; +import scouter.lang.pack.Pack; +import scouter.lang.value.ListValue; +import scouter.net.RequestCmd; + +public class ServiceGroupElapsedView extends AbstractServiceGroupElapsedView { + + public final static String ID = ServiceGroupElapsedView.class.getName(); + + int serverId; + String objType; + String displayObjType; + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + String ids[] = secId.split("&"); + serverId = Integer.valueOf(ids[0]); + objType = ids[1]; + } + + public void createPartControl(Composite parent) { + Server server = ServerManager.getInstance().getServer(serverId); + if (server != null ) displayObjType = server.getCounterEngine().getDisplayNameObjectType(objType); + this.setPartName("Service[Elapsed] - " + displayObjType); + super.createPartControl(parent); + } + + public MapPack fetch() { + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + Pack pack = null; + try { + MapPack param = new MapPack(); + ListValue objLv = param.newList("objHash"); + Map agentMap = AgentModelThread.getInstance().getAgentObjectMap(); + for (AgentObject p : agentMap.values()) { + if (p.getObjType().equals(objType)) { + objLv.add(p.getObjHash()); + } + } + pack = tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); + } catch (Throwable th) { + th.printStackTrace(); + } finally { + TcpProxy.putTcpProxy(tcp); + } + MapPack m = null; + if (pack != null) { + m = (MapPack) pack; + long time = TimeUtil.getCurrentTime(serverId); + m.put("time", time); + } + return m; + } +} diff --git a/scouter.client/src/scouter/client/views/ServiceGroupView.java b/scouter.client/src/scouter/client/views/ServiceGroupTPSView.java similarity index 82% rename from scouter.client/src/scouter/client/views/ServiceGroupView.java rename to scouter.client/src/scouter/client/views/ServiceGroupTPSView.java index 7b9d2f158..9d81d08d3 100644 --- a/scouter.client/src/scouter/client/views/ServiceGroupView.java +++ b/scouter.client/src/scouter/client/views/ServiceGroupTPSView.java @@ -1,99 +1,86 @@ -/* +/* * Copyright 2015 the original author or authors. - * @https://github.com/scouter-project/scouter - * - * 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 scouter.client.views; - -import java.util.Map; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.IViewSite; -import org.eclipse.ui.PartInitException; - -import scouter.client.model.AgentModelThread; -import scouter.client.model.AgentObject; -import scouter.client.net.TcpProxy; -import scouter.client.server.Server; -import scouter.client.server.ServerManager; -import scouter.client.util.TimeUtil; -import scouter.lang.pack.MapPack; -import scouter.lang.pack.Pack; -import scouter.lang.value.ListValue; -import scouter.net.RequestCmd; - -public class ServiceGroupView extends ServiceGroupCommonView { - - public final static String ID = ServiceGroupView.class.getName(); - - int serverId; - String objType; - String displayObjType; - - public void init(IViewSite site) throws PartInitException { - super.init(site); - String secId = site.getSecondaryId(); - String ids[] = secId.split("&"); - serverId = Integer.valueOf(ids[0]); - objType = ids[1]; - } - - public void createPartControl(Composite parent) { - Server server = ServerManager.getInstance().getServer(serverId); - if (server != null ) displayObjType = server.getCounterEngine().getDisplayNameObjectType(objType); - this.setPartName("Service[Throughput] - " + displayObjType); - super.createPartControl(parent); - } - - public MapPack fetch() { - TcpProxy tcp = TcpProxy.getTcpProxy(serverId); - Pack pack = null; - try { - MapPack param = new MapPack(); - ListValue objLv = param.newList("objHash"); - Map agentMap = AgentModelThread.getInstance().getAgentObjectMap(); - for (AgentObject p : agentMap.values()) { - if (p.getObjType().equals(objType)) { - objLv.add(p.getObjHash()); - } - } - pack = tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); - } catch (Throwable th) { - th.printStackTrace(); - } finally { - TcpProxy.putTcpProxy(tcp); - } - MapPack m = null; - if (pack != null) { - m = (MapPack) pack; - long time = TimeUtil.getCurrentTime(serverId); - m.put("time", time); - fiveMinMap.put(time, m); - } - return m; - } - - @Override - public void setTitleName(MODE mode) { - switch (mode) { - case THROUGHPUT: - this.setPartName("Service[Throughput] - " + displayObjType); - break; - case ELASPED: - this.setPartName("Service[Elapsed Time] - " + displayObjType); - break; - } - } -} + * @https://github.com/scouter-project/scouter + * + * 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 scouter.client.views; + +import java.util.Map; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.PartInitException; + +import scouter.client.model.AgentModelThread; +import scouter.client.model.AgentObject; +import scouter.client.net.TcpProxy; +import scouter.client.server.Server; +import scouter.client.server.ServerManager; +import scouter.client.util.TimeUtil; +import scouter.lang.pack.MapPack; +import scouter.lang.pack.Pack; +import scouter.lang.value.ListValue; +import scouter.net.RequestCmd; + +public class ServiceGroupTPSView extends AbstractServiceGroupTPSView { + + public final static String ID = ServiceGroupTPSView.class.getName(); + + int serverId; + String objType; + String displayObjType; + + public void init(IViewSite site) throws PartInitException { + super.init(site); + String secId = site.getSecondaryId(); + String ids[] = secId.split("&"); + serverId = Integer.valueOf(ids[0]); + objType = ids[1]; + } + + public void createPartControl(Composite parent) { + Server server = ServerManager.getInstance().getServer(serverId); + if (server != null ) displayObjType = server.getCounterEngine().getDisplayNameObjectType(objType); + this.setPartName("Service[Throughput] - " + displayObjType); + super.createPartControl(parent); + } + + public MapPack fetch() { + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + Pack pack = null; + try { + MapPack param = new MapPack(); + ListValue objLv = param.newList("objHash"); + Map agentMap = AgentModelThread.getInstance().getAgentObjectMap(); + for (AgentObject p : agentMap.values()) { + if (p.getObjType().equals(objType)) { + objLv.add(p.getObjHash()); + } + } + pack = tcp.getSingle(RequestCmd.REALTIME_SERVICE_GROUP, param); + } catch (Throwable th) { + th.printStackTrace(); + } finally { + TcpProxy.putTcpProxy(tcp); + } + MapPack m = null; + if (pack != null) { + m = (MapPack) pack; + long time = TimeUtil.getCurrentTime(serverId); + m.put("time", time); + } + return m; + } +} From d8deb8868599d31c9f4ec91e4466d8be13b54a7a Mon Sep 17 00:00:00 2001 From: Gunhee Lee Date: Fri, 4 Mar 2016 14:44:43 +0900 Subject: [PATCH 09/11] counter plugin dup bug fix --- scouter.server/src/scouter/server/db/RealtimeCounterWR.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/scouter.server/src/scouter/server/db/RealtimeCounterWR.scala b/scouter.server/src/scouter/server/db/RealtimeCounterWR.scala index 80fc8c40a..65580255e 100644 --- a/scouter.server/src/scouter/server/db/RealtimeCounterWR.scala +++ b/scouter.server/src/scouter/server/db/RealtimeCounterWR.scala @@ -43,7 +43,6 @@ object RealtimeCounterWR { } wdb.activeTime = System.currentTimeMillis(); wdb.counterDbHeader.intern(m.data.keySet()); - PlugInManager.counter(m); val tagbytes = RealtimeCounterDBHelper.getTagBytes(wdb.counterDbHeader.getTagStrInt(), m.data) val posTags = wdb.counterData.write(tagbytes); wdb.counterIndex.write(HashUtil.hash(m.objName), m.time, posTags); From 60775a2d056dc6e940e1290d59ab54f0eec94296 Mon Sep 17 00:00:00 2001 From: KimEunsu Date: Fri, 4 Mar 2016 18:04:32 +0900 Subject: [PATCH 10/11] bug fix - updated object type incorrectly --- .../src/scouter/server/core/AgentManager.scala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scouter.server/src/scouter/server/core/AgentManager.scala b/scouter.server/src/scouter/server/core/AgentManager.scala index 4d8f8bcd1..8447a134f 100644 --- a/scouter.server/src/scouter/server/core/AgentManager.scala +++ b/scouter.server/src/scouter/server/core/AgentManager.scala @@ -81,15 +81,12 @@ object AgentManager { objPack.wakeup(); objPack.tags = p.tags; if (CompareUtil.equals(p.address, objPack.address) == false) { - objPack.address = p.address; save = true; } if (CompareUtil.equals(p.objType, objPack.objType) == false) { - objPack.objType = p.objType; save = true; } if (CompareUtil.equals(p.version, objPack.version) == false) { - objPack.version = p.version; save = true; } if (save) { @@ -97,11 +94,12 @@ object AgentManager { if (objPack.updated % 20 == 0) { alertTooManyChange(objPack); } - - objMap.put(objPack); - procObjName(objPack); - ObjectWR.add(objPack); - Logger.println("S105", "Update " + objPack); + p.updated = objPack.updated; + p.wakeup(); + objMap.put(p); + procObjName(p); + ObjectWR.add(p); + Logger.println("S105", "Update " + p); } } } From 95b2d4377770ba2b2eaa47dc1f0141c146826df6 Mon Sep 17 00:00:00 2001 From: Gunhee Lee Date: Sat, 5 Mar 2016 22:06:06 +0900 Subject: [PATCH 11/11] documentation about live demo --- README.md | 11 +++++-- README_kr.md | 10 ++++-- scouter.common/pom.xml | 29 ++++++++++++++++++ .../img/main/live-demo-client-login.png | Bin 0 -> 34586 bytes scouter.document/main/Live-Demo.md | 14 +++++++++ scouter.document/main/Live-Demo_kr.md | 16 ++++++++++ 6 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 scouter.common/pom.xml create mode 100644 scouter.document/img/main/live-demo-client-login.png create mode 100644 scouter.document/main/Live-Demo.md create mode 100644 scouter.document/main/Live-Demo_kr.md diff --git a/README.md b/README.md index 63f4ea02f..256777f03 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ SCOUTER can help you. ## Documents - [Document Home](./scouter.document/index.md) - [Quick Start Guide (Quick Installation and Demo)](./scouter.document/main/Quick-Start.md) + - [Live Demo(Try to use scouter by connecting on live demo system)](./scouter.document/main/Live-Demo.md) - [Client Screen Help](./scouter.document/client/How-To-Use-Client.md) ## Download @@ -67,12 +68,16 @@ Scouter has three modules: - **SWT & GEF4** : Charts and Diagrams
+## Facebook + - [Scouter APM : Facebook Scouter user group](https://www.facebook.com/groups/scouterapm/) + +## How to contribute + - TBD + + ## Q&A - [Google Groups](https://groups.google.com/forum/#!forum/scouter-project) -## Facebook - - [Facebook Scouter user group](https://www.facebook.com/groups/1525329794448529/) - ## License Licensed under the Apache License, Version 2.0
diff --git a/README_kr.md b/README_kr.md index 543d81033..22733723e 100644 --- a/README_kr.md +++ b/README_kr.md @@ -30,6 +30,7 @@ APM은 Application performance montoring 또는 application performance manageme ## Documents - [Document Home](./scouter.document/index_kr.md) - [Quick Start(Scouter Demo 설치)](./scouter.document/main/Quick-Start_kr.md) + - [Live Demo(제공되는 Demo 시스템 바로 접속해 보기)](./scouter.document/main/Live-Demo_kr.md) - [Client 화면 설명](./scouter.document/client/How-To-Use-Client_kr.md) ## Download @@ -62,12 +63,15 @@ APM은 Application performance montoring 또는 application performance manageme - **SWT & GEF4** : Charts and Diagrams
+## Facebook + - [Scouter APM 사용자 모임 - Facebook 그룹](https://www.facebook.com/groups/scouterapm/) + +## Scouter에 기여하기 + - TBD + ## Q&A - [Google Groups](https://groups.google.com/forum/#!forum/scouter-project) -## Facebook - - [Facebook Scouter user group](https://www.facebook.com/groups/1525329794448529/) - ## License Licensed under the Apache License, Version 2.0
diff --git a/scouter.common/pom.xml b/scouter.common/pom.xml new file mode 100644 index 000000000..e28dd93d2 --- /dev/null +++ b/scouter.common/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + scouter + common + 1.0 + jar + scouter-common + + + UTF-8 + + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 2.3.0 + test + + + diff --git a/scouter.document/img/main/live-demo-client-login.png b/scouter.document/img/main/live-demo-client-login.png new file mode 100644 index 0000000000000000000000000000000000000000..d133c30c8afbdae416638c8c9cfca45146ef0b03 GIT binary patch literal 34586 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 a{aL?>efc5wH|(<*fWXt$&t;ucLK6Vb@>mN1 literal 0 HcmV?d00001 diff --git a/scouter.document/main/Live-Demo.md b/scouter.document/main/Live-Demo.md new file mode 100644 index 000000000..6cb6053da --- /dev/null +++ b/scouter.document/main/Live-Demo.md @@ -0,0 +1,14 @@ +# Quick Start +![Englsh](https://img.shields.io/badge/language-English-red.svg) [![Korean](https://img.shields.io/badge/language-Korean-blue.svg)](Live-Demo_kr.md) + +There is pre-built scouter live demo system that you can connect to. +Try to do via scouter client v0.4.6 and you can download the client by the link below. + +1. [Download Client(Viewer)](https://github.com/scouter-project/scouter/releases/tag/v0.4.6) +2. Extract the compressed file you downloaded, run the client and connect to the live demo server by the given information. + - Server server address : demo.scouterapm.com:6100 + - ID : scouter + - Password : scouter + +![login](../img/main/live-demo-client-login.png) + diff --git a/scouter.document/main/Live-Demo_kr.md b/scouter.document/main/Live-Demo_kr.md new file mode 100644 index 000000000..4db7ad3f7 --- /dev/null +++ b/scouter.document/main/Live-Demo_kr.md @@ -0,0 +1,16 @@ +# Quick Start +[![Englsh](https://img.shields.io/badge/language-English-red.svg)](Live-Demo.md) ![Korean](https://img.shields.io/badge/language-Korean-blue.svg) + +Scouter를 바로 사용해 볼 수 있도록 Live 데모 시스템이 구성되어 있으며 +클라이언트만 다운로드 하여 접속해 볼 수 있다 + +현재 Live 데모 시스템은 v0.4.6으로 구성되어 있으므로 v0.4.6 클라이언트로 접속하여 볼 수 있다 + +1. [Client(Viewer) 다운로드](https://github.com/scouter-project/scouter/releases/tag/v0.4.6) +2. Client 실행하고 아래 정보를 입력하여 Scouter 데모 서버로 접속한다. + - Server 주소 : demo.scouterapm.com:6100 + - ID : scouter + - Password : scouter + +![login](../img/main/live-demo-client-login.png) +