diff --git a/scouter.agent.batch/src/main/java/scouter/agent/batch/Configure.java b/scouter.agent.batch/src/main/java/scouter/agent/batch/Configure.java index dee84d3d7..b22b55bd7 100644 --- a/scouter.agent.batch/src/main/java/scouter/agent/batch/Configure.java +++ b/scouter.agent.batch/src/main/java/scouter/agent/batch/Configure.java @@ -16,20 +16,11 @@ */ package scouter.agent.batch; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; - import scouter.agent.util.JarUtil; import scouter.lang.conf.ConfigDesc; +import scouter.lang.conf.ConfigValueType; import scouter.lang.conf.ConfigValueUtil; +import scouter.lang.conf.ValueType; import scouter.lang.counters.CounterConstants; import scouter.lang.value.ListValue; import scouter.lang.value.MapValue; @@ -43,6 +34,17 @@ import scouter.util.SysJMX; import scouter.util.SystemUtil; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; + public class Configure { public static final String CONFIG_SCOUTER_ENABLED = "scouter_enabled"; public static final String VM_SCOUTER_ENABLED = "scouter.enabled"; @@ -89,10 +91,13 @@ public final static synchronized Configure getInstance() { @ConfigDesc("SQL max count") public int sql_max_count = 100; @ConfigDesc("Method set for preparestatement hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_pstmt_classes = ""; - @ConfigDesc("Method set for statement hooking") + @ConfigDesc("Method set for statement hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_stmt_classes = ""; - @ConfigDesc("Method set for resultset hooking") + @ConfigDesc("Method set for resultset hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_rs_classes = ""; // SFA(Stack Frequency Analyzer) Thread Dump @@ -506,7 +511,11 @@ public MapValue getKeyValueInfo() { public StringKeyLinkedMap getConfigureDesc() { return ConfigValueUtil.getConfigDescMap(this); - } + } + + public StringKeyLinkedMap getConfigureValueType() { + return ConfigValueUtil.getConfigValueTypeMap(this); + } private static HashSet ignoreSet = new HashSet(); static { diff --git a/scouter.agent.batch/src/main/java/scouter/agent/batch/netio/request/handle/AgentConfigure.java b/scouter.agent.batch/src/main/java/scouter/agent/batch/netio/request/handle/AgentConfigure.java index 5ef9e421b..eca32a750 100644 --- a/scouter.agent.batch/src/main/java/scouter/agent/batch/netio/request/handle/AgentConfigure.java +++ b/scouter.agent.batch/src/main/java/scouter/agent/batch/netio/request/handle/AgentConfigure.java @@ -17,14 +17,10 @@ package scouter.agent.batch.netio.request.handle; -import java.lang.instrument.ClassDefinition; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; - import scouter.agent.batch.Configure; import scouter.agent.batch.JavaAgent; import scouter.agent.netio.request.anotation.RequestHandler; +import scouter.lang.conf.ValueType; import scouter.lang.pack.MapPack; import scouter.lang.pack.Pack; import scouter.lang.value.BooleanValue; @@ -35,6 +31,11 @@ import scouter.util.StringKeyLinkedMap; import scouter.util.StringKeyLinkedMap.StringKeyLinkedEntry; +import java.lang.instrument.ClassDefinition; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; + public class AgentConfigure { @RequestHandler(RequestCmd.GET_CONFIGURE_WAS) @@ -129,4 +130,16 @@ public Pack getConfigureDesc(Pack param) { } return pack; } -} \ No newline at end of file + + @RequestHandler(RequestCmd.CONFIGURE_VALUE_TYPE) + public Pack getConfigureValueType(Pack param) { + StringKeyLinkedMap valueTypeMap = Configure.getInstance().getConfigureValueType(); + MapPack pack = new MapPack(); + Enumeration> entries = valueTypeMap.entries(); + while (entries.hasMoreElements()) { + StringKeyLinkedEntry entry = entries.nextElement(); + pack.put(entry.getKey(), entry.getValue().getType()); + } + return pack; + } +} diff --git a/scouter.agent.host/src/main/java/scouter/agent/Configure.java b/scouter.agent.host/src/main/java/scouter/agent/Configure.java index b44682b38..2bad91b7d 100644 --- a/scouter.agent.host/src/main/java/scouter/agent/Configure.java +++ b/scouter.agent.host/src/main/java/scouter/agent/Configure.java @@ -21,14 +21,29 @@ import scouter.agent.netio.data.DataProxy; import scouter.lang.conf.ConfObserver; import scouter.lang.conf.ConfigDesc; +import scouter.lang.conf.ConfigValueType; import scouter.lang.conf.ConfigValueUtil; +import scouter.lang.conf.ValueType; import scouter.lang.counters.CounterConstants; import scouter.lang.value.ListValue; import scouter.lang.value.MapValue; import scouter.net.NetConstants; -import scouter.util.*; - -import java.io.*; +import scouter.util.DateUtil; +import scouter.util.FileUtil; +import scouter.util.HashUtil; +import scouter.util.StringEnumer; +import scouter.util.StringKeyLinkedMap; +import scouter.util.StringSet; +import scouter.util.StringUtil; +import scouter.util.SysJMX; +import scouter.util.SystemUtil; +import scouter.util.ThreadUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -79,6 +94,7 @@ public final static synchronized Configure getInstance() { //Manager @ConfigDesc("") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public StringSet mgr_log_ignore_ids = new StringSet(); //Counter @@ -423,6 +439,10 @@ public StringKeyLinkedMap getConfigureDesc() { return ConfigValueUtil.getConfigDescMap(this); } + public StringKeyLinkedMap getConfigureValueType() { + return ConfigValueUtil.getConfigValueTypeMap(this); + } + public static void main(String[] args) { Configure o = new Configure(true); StringKeyLinkedMap defMap = ConfigValueUtil.getConfigDefault(o); diff --git a/scouter.agent.host/src/main/java/scouter/agent/netio/request/handle/HostAgentConfigure.java b/scouter.agent.host/src/main/java/scouter/agent/netio/request/handle/HostAgentConfigure.java index 08d35e82f..0be1021a4 100644 --- a/scouter.agent.host/src/main/java/scouter/agent/netio/request/handle/HostAgentConfigure.java +++ b/scouter.agent.host/src/main/java/scouter/agent/netio/request/handle/HostAgentConfigure.java @@ -17,10 +17,9 @@ package scouter.agent.netio.request.handle; -import java.util.Enumeration; - import scouter.agent.Configure; import scouter.agent.netio.request.anotation.RequestHandler; +import scouter.lang.conf.ValueType; import scouter.lang.pack.MapPack; import scouter.lang.pack.Pack; import scouter.lang.value.MapValue; @@ -28,6 +27,8 @@ import scouter.util.StringKeyLinkedMap; import scouter.util.StringKeyLinkedMap.StringKeyLinkedEntry; +import java.util.Enumeration; + public class HostAgentConfigure { @RequestHandler(RequestCmd.GET_CONFIGURE_WAS) @@ -79,4 +80,16 @@ public Pack getConfigureDesc(Pack param) { } return pack; } -} \ No newline at end of file + + @RequestHandler(RequestCmd.CONFIGURE_VALUE_TYPE) + public Pack getConfigureValueType(Pack param) { + StringKeyLinkedMap valueTypeMap = Configure.getInstance().getConfigureValueType(); + MapPack pack = new MapPack(); + Enumeration> entries = valueTypeMap.entries(); + while (entries.hasMoreElements()) { + StringKeyLinkedEntry entry = entries.nextElement(); + pack.put(entry.getKey(), entry.getValue().getType()); + } + return pack; + } +} diff --git a/scouter.agent.java/src/main/java/scouter/agent/Configure.java b/scouter.agent.java/src/main/java/scouter/agent/Configure.java index bea3340b9..f15c3e247 100644 --- a/scouter.agent.java/src/main/java/scouter/agent/Configure.java +++ b/scouter.agent.java/src/main/java/scouter/agent/Configure.java @@ -21,7 +21,9 @@ import scouter.agent.util.JarUtil; import scouter.lang.conf.ConfObserver; import scouter.lang.conf.ConfigDesc; +import scouter.lang.conf.ConfigValueType; import scouter.lang.conf.ConfigValueUtil; +import scouter.lang.conf.ValueType; import scouter.lang.counters.CounterConstants; import scouter.lang.value.ListValue; import scouter.lang.value.MapValue; @@ -124,8 +126,11 @@ public final static synchronized Configure getInstance() { public boolean profile_http_header_enabled; @ConfigDesc("Service URL prefix for Http header profile") public String profile_http_header_url_prefix = "/"; + @ConfigDesc("http header names for profiling with comma separator") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String profile_http_header_keys = ""; + @ConfigDesc("Http Parameter profile") public boolean profile_http_parameter_enabled; @ConfigDesc("Service URL prefix for Http parameter profile") @@ -164,7 +169,8 @@ public final static synchronized Configure getInstance() { public boolean profile_fullstack_hooked_exception_enabled = false; @ConfigDesc("Number of stack profile lines in occurrence of error") public int profile_fullstack_max_lines = 0; - @ConfigDesc("Activating SQL literal task") + + @ConfigDesc("Escaping literal parameters for normalizing the query") public boolean profile_sql_escape_enabled = true; @ConfigDesc("") public boolean _profile_fullstack_sql_connection_enabled = false; @@ -251,8 +257,10 @@ public final static synchronized Configure getInstance() { //Manager @ConfigDesc("") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String mgr_static_content_extensions = "js, htm, html, gif, png, jpg, css"; @ConfigDesc("") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String mgr_log_ignore_ids = ""; //Auto dump options when active service is exceed the set threshold count. @@ -329,8 +337,11 @@ public final static synchronized Configure getInstance() { //XLog sampling for service patterns options @ConfigDesc("XLog patterned sampling mode enabled") public boolean xlog_patterned_sampling_enabled = false; + @ConfigDesc("XLog patterned sampling service patterns\neg) /user/{userId},/device/*") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String xlog_patterned_sampling_service_patterns = ""; + @ConfigDesc("XLog patterned sampling but discard profile only not XLog.") public boolean xlog_patterned_sampling_only_profile = false; @ConfigDesc("XLog patterned sampling bound millisecond - step1(lowest : range - from 0 to here)") @@ -350,6 +361,7 @@ public final static synchronized Configure getInstance() { //XLog discard options @ConfigDesc("XLog discard service patterns\nNo XLog data, but apply to TPS and summary.\neg) /user/{userId},/device/*") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String xlog_discard_service_patterns = ""; //Alert @@ -386,23 +398,41 @@ public final static synchronized Configure getInstance() { //Hook @ConfigDesc("Method set for argument hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_args_patterns = ""; + @ConfigDesc("Method set for return hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_return_patterns = ""; + @ConfigDesc("Method set for constructor hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_constructor_patterns = ""; + @ConfigDesc("Method set for dbconnection hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_connection_open_patterns = ""; + @ConfigDesc("IntialContext Class Set") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_context_classes = "javax/naming/InitialContext"; + @ConfigDesc("Method set for method hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_method_patterns = ""; + @ConfigDesc("Prefix without Method hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_method_ignore_prefixes = "get,set"; + @ConfigDesc("Class set without Method hookingt") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_method_ignore_classes = ""; + @ConfigDesc("") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_method_exclude_patterns = ""; + @ConfigDesc("Activating public Method hooking") public boolean hook_method_access_public_enabled = true; @ConfigDesc("Activating private Method hooking") @@ -413,50 +443,82 @@ public final static synchronized Configure getInstance() { public boolean hook_method_access_none_enabled = false; @ConfigDesc("Activating lambda Method hooking") public boolean hook_method_lambda_enable = true; + @ConfigDesc("Method set for service hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_service_patterns = ""; + @ConfigDesc("Method set for apicall hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_apicall_patterns = ""; + @ConfigDesc("Method set for apicallinfo hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_apicall_info_patterns = ""; + @ConfigDesc("Method set for jsp hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jsp_patterns = ""; + @ConfigDesc("Method set for preparestatement hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_pstmt_classes = ""; + @ConfigDesc("Method set for statement hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_stmt_classes = ""; + @ConfigDesc("Method set for resultset hooking") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_rs_classes = ""; + @ConfigDesc("Method set for dbconnection wrapping") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_jdbc_wrapping_driver_patterns = ""; + @ConfigDesc("Exception class patterns - These will seem as error on xlog view.\n (ex) my.app.BizException,my.app.exception.*Exception") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_exception_class_patterns = ""; + @ConfigDesc("Exception class exclude patterns") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_exception_exclude_class_patterns = ""; + @ConfigDesc("Exception handler patterns\n - exceptions passed to these methods are treated as error on xlog view.\n (ex) my.app.myHandler.handleException") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_exception_handler_method_patterns = ""; + @ConfigDesc("Exception handler exclude class name patterns(can not include star-* in patterns)\n - (ex) my.app.MyManagedException,MyBizException") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_exception_handler_exclude_class_patterns = ""; @ConfigDesc("Hook for supporting async servlet") public boolean hook_async_servlet_enabled = true; + @ConfigDesc("startAsync impl. method patterns") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_async_servlet_start_patterns = ""; + @ConfigDesc("asyncContext dispatch impl. method patterns") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_async_context_dispatch_patterns = ""; @ConfigDesc("spring async execution submit patterns") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_spring_async_submit_patterns = ""; + @ConfigDesc("spring async execution hook enabled") public boolean hook_spring_async_enabled = true; @Deprecated @ConfigDesc("Deprecated. use hook_async_callrunnable_enabled") public boolean hook_async_callrunnable_enable = true; + @ConfigDesc("Hook callable and runnable for tracing async processing.\n It hook only 'hook_async_callrunnable_scan_prefixes' option contains pacakage or classes") public boolean hook_async_callrunnable_enabled = true; @ConfigDesc("scanning range prefixes for hooking callable, runnable implementations and lambda expressions.\n usually your application package.\n 2 or more packages can be separated by commas.") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public String hook_async_callrunnable_scan_package_prefixes = ""; @ConfigDesc("PRE-released option before stable release!\nhook threadpool executor for tracing async processing.") @@ -1190,6 +1252,10 @@ public StringKeyLinkedMap getConfigureDesc() { return ConfigValueUtil.getConfigDescMap(this); } + public StringKeyLinkedMap getConfigureValueType() { + return ConfigValueUtil.getConfigValueTypeMap(this); + } + public int getHookSignature() { return this.hook_signature; } diff --git a/scouter.agent.java/src/main/java/scouter/agent/netio/request/handle/AgentConfigure.java b/scouter.agent.java/src/main/java/scouter/agent/netio/request/handle/AgentConfigure.java index 05a62b1de..d157b6e59 100644 --- a/scouter.agent.java/src/main/java/scouter/agent/netio/request/handle/AgentConfigure.java +++ b/scouter.agent.java/src/main/java/scouter/agent/netio/request/handle/AgentConfigure.java @@ -20,6 +20,7 @@ import scouter.agent.Configure; import scouter.agent.JavaAgent; import scouter.agent.netio.request.anotation.RequestHandler; +import scouter.lang.conf.ValueType; import scouter.lang.pack.MapPack; import scouter.lang.pack.Pack; import scouter.lang.value.BooleanValue; @@ -174,4 +175,16 @@ public Pack getConfigureDesc(Pack param) { } return pack; } -} \ No newline at end of file + + @RequestHandler(RequestCmd.CONFIGURE_VALUE_TYPE) + public Pack getConfigureValueType(Pack param) { + StringKeyLinkedMap valueTypeMap = Configure.getInstance().getConfigureValueType(); + MapPack pack = new MapPack(); + Enumeration> entries = valueTypeMap.entries(); + while (entries.hasMoreElements()) { + StringKeyLinkedEntry entry = entries.nextElement(); + pack.put(entry.getKey(), entry.getValue().getType()); + } + return pack; + } +} diff --git a/scouter.client/src/scouter/client/configuration/views/ConfigureItemDialog.java b/scouter.client/src/scouter/client/configuration/views/ConfigureItemDialog.java new file mode 100644 index 000000000..d59f50180 --- /dev/null +++ b/scouter.client/src/scouter/client/configuration/views/ConfigureItemDialog.java @@ -0,0 +1,175 @@ +/* +* 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.configuration.views; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import scouter.lang.conf.ValueType; +import scouter.util.StringUtil; + +public class ConfigureItemDialog extends TitleAreaDialog { + String confKey; + String valueOrg; + String objName; + String desc; + ValueType valueType; + + String value; + + public ConfigureItemDialog(Shell parentShell, String confKey, String valueOrg, String objName, String desc, ValueType valueType) { + super(parentShell); + this.confKey = confKey; + this.objName = objName; + this.desc = desc; + this.valueType = (valueType == null) ? ValueType.VALUE : valueType; + this.valueOrg = valueOrg; + this.value = shape(valueOrg); + } + + @Override + public void create() { + super.create(); + setTitle("\"" + confKey + "\" (" + objName + ")"); + + if (StringUtil.isNotEmpty(desc)) { + setMessage(desc, IMessageProvider.INFORMATION); + } else { + setMessage("Set the value of : " + confKey, IMessageProvider.INFORMATION); + } + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite container = (Composite) super.createDialogArea(parent); + setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE); + setBlockOnOpen(true); + container.setLayout(new GridLayout(1, true)); + + Group group = new Group(container, SWT.NONE); + group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + group.setLayout(new GridLayout(1, false)); + +// Label label = new Label(filterGrp, SWT.NONE); +// label.setText("Service"); +// label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); + + if (valueType == ValueType.VALUE) { + Text serviceTxt = new Text(group, SWT.BORDER | SWT.SINGLE); + serviceTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + serviceTxt.setText(value); + serviceTxt.addModifyListener(e -> value = ((Text) e.getSource()).getText()); + } else if (valueType == ValueType.COMMA_SEPARATED_VALUE) { + Text serviceTxt = new Text(group, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint = 100; + serviceTxt.setLayoutData(gridData); + serviceTxt.setText(value); + serviceTxt.addModifyListener(e -> value = ((Text) e.getSource()).getText()); + } else if (valueType == ValueType.NUM) { + Text serviceTxt = new Text(group, SWT.BORDER | SWT.SINGLE); + serviceTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + serviceTxt.addVerifyListener(e -> e.doit = isNumber(e.text)); + serviceTxt.setText(value); + serviceTxt.addModifyListener(e -> value = ((Text) e.getSource()).getText()); + } else if (valueType == ValueType.BOOL) { + Button button = new Button(group, SWT.CHECK); + button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + button.setText(confKey); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (((Button) e.widget).getSelection()) { + value = "true"; + } else { + value = "false"; + } + } + }); + button.setSelection("true".equals(value)); + } else { + Text serviceTxt = new Text(group, SWT.BORDER | SWT.SINGLE); + serviceTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + serviceTxt.setText(value); + serviceTxt.addModifyListener(e -> value = ((Text) e.getSource()).getText()); + } + + return container; + } + + private boolean isNumber(String v) { + char[] chars = new char[v.length()]; + v.getChars(0, chars.length, chars, 0); + for (int i = 0; i < chars.length; i++) { + if (!('0' <= chars[i] && chars[i] <= '9')) { + return false; + } + } + return true; + } + + @Override + protected void okPressed() { + super.okPressed(); + } + + @Override + protected Point getInitialSize() { + return getShell().computeSize(600, SWT.DEFAULT); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Configure item detail"); + } + + @Override + protected boolean isResizable() { + return true; + } + + private String unShape(String value0) { + if(valueType == ValueType.COMMA_SEPARATED_VALUE) { + return value0.replaceAll("\\s+", ","); + } + return value0; + } + + private String shape(String value0) { + if(valueType == ValueType.COMMA_SEPARATED_VALUE) { + return value0.replace(',', '\n'); + } + return value0; + } + + public String getValue() { + return unShape(value); + } +} diff --git a/scouter.client/src/scouter/client/configuration/views/ConfigureView.java b/scouter.client/src/scouter/client/configuration/views/ConfigureView.java index db29e5bad..9a27419fd 100644 --- a/scouter.client/src/scouter/client/configuration/views/ConfigureView.java +++ b/scouter.client/src/scouter/client/configuration/views/ConfigureView.java @@ -22,21 +22,45 @@ import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.*; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.DefaultToolTip; +import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.events.*; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.*; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import scouter.client.Images; @@ -45,7 +69,12 @@ import scouter.client.server.Server; import scouter.client.server.ServerManager; import scouter.client.sorter.ColumnLabelSorter; -import scouter.client.util.*; +import scouter.client.util.ColoringWord; +import scouter.client.util.ConsoleProxy; +import scouter.client.util.CustomLineStyleListener; +import scouter.client.util.ExUtil; +import scouter.client.util.ImageUtil; +import scouter.lang.conf.ValueType; import scouter.lang.pack.MapPack; import scouter.lang.value.ListValue; import scouter.net.RequestCmd; @@ -54,6 +83,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -61,11 +91,18 @@ public class ConfigureView extends ViewPart { public final static String ID = ConfigureView.class.getName(); private ArrayList defaultHighlightings; + private HashSet configKeyNames = new HashSet<>(); private StyledText text; private String content; private int serverId; private int objHash; + private String displayName; + + private volatile String selectedText = ""; + private volatile long selectedTime = 0L; + private volatile int selectedX = 0; + private volatile int selectedY = 0; Composite listComp; TableViewer viewer; @@ -81,6 +118,7 @@ public class ConfigureView extends ViewPart { boolean devMode; HashMap descMap = new HashMap(); + HashMap valueTypeMap = new HashMap(); public void createPartControl(Composite parent) { parent.setLayout(new FillLayout()); @@ -99,7 +137,6 @@ public void createPartControl(Composite parent) { searchLabel.setText("Filter : "); searchTxt = new Text(searchComp, SWT.BORDER); -// searchTxt = new Text(listComp, SWT.BORDER); searchTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); searchTxt.setToolTipText("Search Key/Value"); searchTxt.addMouseListener(new MouseListener() { @@ -216,12 +253,12 @@ public void keyPressed(KeyEvent e) { Label bottomLabel = new Label(listComp, SWT.BORDER); bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - bottomLabel.setFont(new Font(null, "Arial", 10, SWT.BOLD)); + bottomLabel.setFont(new Font(null, "Arial", 11, SWT.BOLD | SWT.ITALIC)); bottomLabel.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); bottomLabel.setText(new StringBuilder() - .append("- click for tooltip\n") - .append("- dbl-click for copy && paste (or ctl+C)") + .append(" [Click] for tooltip\n") + .append(" [Double-Click] for copy && paste (or ctl+C)") .toString()); sashForm.setWeights(new int[] {1, 1}); @@ -233,10 +270,12 @@ public void setInput(int serverId){ this.serverId = serverId; Server server = ServerManager.getInstance().getServer(serverId); if (server != null) { + this.displayName = server.getName(); setPartName("Config Server[" + server.getName() + "]"); loadConfig(RequestCmd.GET_CONFIGURE_SERVER, null); loadConfigList(RequestCmd.LIST_CONFIGURE_SERVER, null); loadConfigDesc(new MapPack()); + loadConfigValueType(new MapPack()); } } @@ -245,17 +284,24 @@ public void setInput(int serverId, int objHash){ this.objHash = objHash; Server server = ServerManager.getInstance().getServer(serverId); if (server != null) { + this.displayName = TextProxy.object.getText(objHash); setPartName("Config Agent[" + TextProxy.object.getText(objHash) + "]"); MapPack param = new MapPack(); param.put("objHash", objHash); loadConfig(RequestCmd.GET_CONFIGURE_WAS, param); loadConfigList(RequestCmd.LIST_CONFIGURE_WAS, param); loadConfigDesc(param); + loadConfigValueType(param); } } private void initialStyledText(Composite parent) { - text = new StyledText(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + Composite comp = new Composite(parent, SWT.NONE); + comp.setLayout(new GridLayout(1, true)); + + text = new StyledText(comp, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + listener = new CustomLineStyleListener(true, defaultHighlightings, false); text.addLineStyleListener(listener); text.addKeyListener(new KeyListener() { @@ -271,6 +317,74 @@ public void keyPressed(KeyEvent e) { } } }); + text.addMouseListener(new MouseAdapter() { + @Override + public void mouseDoubleClick(MouseEvent e) { + if (selectedTime > System.currentTimeMillis() - 1500) { + if (configKeyNames.contains(selectedText)) { + String fullText = text.getText(); + String textToIt = fullText.substring(0, selectedX); + int lastIndexOfLineBreakToIt = textToIt.lastIndexOf('\n'); + if (lastIndexOfLineBreakToIt >= 0) { + if(fullText.charAt(lastIndexOfLineBreakToIt+1) == '#') { + return; + } + } else { + if (textToIt.length() > 0 && textToIt.charAt(0) == '#') { + return; + } + } + + String value = fullText.substring(selectedY); + int startPos = value.indexOf('=')+1; + int lineEndPos = value.indexOf('\n'); + if (lineEndPos >= 0) { + value = value.substring(startPos, lineEndPos); + } else { + value = value.substring(startPos); + } + + ConfigureItemDialog dialog = new ConfigureItemDialog(parent.getShell(), selectedText, value, displayName, + descMap.get(selectedText), valueTypeMap.get(selectedText)); + if (dialog.open() == Window.OK) { + setTheConfig(selectedText, dialog.getValue()); + } + } + } + } + }); + text.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if(e.x == e.y) return; + selectedText = text.getText(e.x, e.y-1); + selectedTime = System.currentTimeMillis(); + selectedX = e.x; + selectedY = e.y; + } + }); + + Label bottomLabel = new Label(comp, SWT.BORDER); + bottomLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + bottomLabel.setFont(new Font(null, "Arial", 11, SWT.BOLD | SWT.ITALIC)); + + bottomLabel.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + bottomLabel.setText(new StringBuilder() + .append(" [Double-Click] the config KEY for popup editor\n") + .append(" ") + .toString()); + } + + private void setTheConfig(String confKey, String confValue) { + if ("null".equals(confValue)) { + confValue = ""; + } + + String content = text.getText(); + String expression = "(?m)^" + confKey + "\\s*=.*\\n?"; + String replacement = confKey + "=" + confValue + "\n"; + content = content.replaceAll(expression, replacement); + text.setText(content); } private void saveConfigurations(){ @@ -339,6 +453,7 @@ public void run() { defaultHighlightings = new ArrayList(); for(int inx = 0 ; configKey != null && inx < configKey.size(); inx++){ defaultHighlightings.add(new ColoringWord(configKey.getString(inx), SWT.COLOR_BLUE, true)); + configKeyNames.add(configKey.getString(inx)); } defaultHighlightings.add(new ColoringWord(";", SWT.COLOR_RED, true)); @@ -419,6 +534,29 @@ public void run() { } }); } + + private void loadConfigValueType(final MapPack param) { + ExUtil.asyncRun(new Runnable() { + public void run() { + MapPack pack = null; + TcpProxy tcp = TcpProxy.getTcpProxy(serverId); + try { + pack = (MapPack) tcp.getSingle(RequestCmd.CONFIGURE_VALUE_TYPE, param); + } catch (Exception e) { + e.printStackTrace(); + } finally { + TcpProxy.putTcpProxy(tcp); + } + if (pack != null) { + Iterator keys = pack.keys(); + while (keys.hasNext()) { + String key = keys.next(); + valueTypeMap.put(key, ValueType.of(pack.getInt(key))); + } + } + } + }); + } public void setFocus() { IStatusLineManager slManager= getViewSite().getActionBars().getStatusLineManager(); diff --git a/scouter.client/src/scouter/client/model/TextProxy.java b/scouter.client/src/scouter/client/model/TextProxy.java index 84cd5aff6..d0691f62c 100644 --- a/scouter.client/src/scouter/client/model/TextProxy.java +++ b/scouter.client/src/scouter/client/model/TextProxy.java @@ -38,7 +38,7 @@ public TextProxy() { final public static TextModel userAgent = new TextModel(TextTypes.USER_AGENT, 1024*20); final public static TextModel group = new TextModel(TextTypes.GROUP, 1024); final public static TextModel sql_tables = new TextModel(TextTypes.SQL_TABLES, 1024); - final public static TextModel city = new TextModel(TextTypes.CITY, 1024); + final public static TextModel city = new TextModel(TextTypes.CITY, 8192); final public static TextModel maria = new TextModel(TextTypes.MARIA, 1024); final public static TextModel web = new TextModel(TextTypes.WEB, 500); final public static TextModel login = new TextModel(TextTypes.LOGIN, 1024*10); diff --git a/scouter.client/src/scouter/client/preferences/ChartPreferencePage.java b/scouter.client/src/scouter/client/preferences/ChartPreferencePage.java index 364cc642a..e2021905e 100644 --- a/scouter.client/src/scouter/client/preferences/ChartPreferencePage.java +++ b/scouter.client/src/scouter/client/preferences/ChartPreferencePage.java @@ -21,19 +21,17 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.*; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; - import scouter.client.Activator; import scouter.client.message.M; import scouter.client.util.UIUtil; +import scouter.client.xlog.views.XLogColumnEnum; import scouter.util.CastUtil; +import java.util.HashMap; + public class ChartPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { GridData gdata; @@ -42,13 +40,16 @@ public class ChartPreferencePage extends FieldEditorPreferencePage implements IW Text xlogIgnoreTxt; Text xlogMxCntTxt; Text xlogMxDragCntTxt; - + int xLogIgnoreTime; int xLogMaxCount; int xLogDragMaxCount; - + + HashMap xLogColumnVisibleMap = new HashMap<>(); + HashMap xLogColumnCheckButtonMap = new HashMap<>(); + private int lineWidth; - + public ChartPreferencePage() { super(); noDefaultAndApplyButton(); @@ -59,10 +60,10 @@ public ChartPreferencePage() { @Override protected Control createContents(Composite parent) { - ((GridLayout)parent.getLayout()).marginBottom = 30; + ((GridLayout)parent.getLayout()).marginBottom = 0; final Group layoutGroup = new Group(parent, SWT.NONE); - layoutGroup.setText(M.PREFERENCE_CHARTSETTING); + layoutGroup.setText(M.PREFERENCE_CHARTSETTING); layoutGroup.setLayout(UIUtil.formLayout(5, 5)); gdata = new GridData(); @@ -71,42 +72,66 @@ protected Control createContents(Composite parent) { IntegerVerifyListener verifyListener = new IntegerVerifyListener(); - Label lineWidthLbl = new Label(layoutGroup, SWT.RIGHT); lineWidthLbl.setText(M.PREFERENCE_CHARTLINE_WIDTH); - lineWidthLbl.setLayoutData(UIUtil.formData(null, -1, 0, 10, null, -1, null, -1, 160)); + lineWidthLbl.setLayoutData(UIUtil.formData(null, -1, 0, 0, null, -1, null, -1, 160)); lineWidthTxt = new Text(layoutGroup, SWT.BORDER); lineWidthTxt.setText(""+lineWidth); //$NON-NLS-1$ - lineWidthTxt.setLayoutData(UIUtil.formData(lineWidthLbl, 10, 0, 8, 100, -5, null, -1)); + lineWidthTxt.setLayoutData(UIUtil.formData(lineWidthLbl, 10, 0, -2, 100, -5, null, -1)); lineWidthTxt.addVerifyListener(verifyListener); Label ignoreLbl = new Label(layoutGroup, SWT.RIGHT); ignoreLbl.setText(M.PREFERENCE_CHARTXLOG_IGNORE_TIME); - ignoreLbl.setLayoutData(UIUtil.formData(null, -1, lineWidthTxt, 10, null, -1, null, -1, 160)); + ignoreLbl.setLayoutData(UIUtil.formData(null, -1, lineWidthTxt, 5, null, -1, null, -1, 160)); xlogIgnoreTxt = new Text(layoutGroup, SWT.BORDER); xlogIgnoreTxt.setText(Integer.toString(xLogIgnoreTime)); - xlogIgnoreTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, lineWidthTxt, 8, 100, -5, null, -1, 150)); + xlogIgnoreTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, lineWidthTxt, 3, 100, -5, null, -1, 150)); xlogIgnoreTxt.addVerifyListener(verifyListener); Label maxCntLbl = new Label(layoutGroup, SWT.RIGHT); maxCntLbl.setText(M.PREFERENCE_CHARTXLOG_MAX_COUNT); - maxCntLbl.setLayoutData(UIUtil.formData(null, -1, xlogIgnoreTxt, 10, null, -1, null, -1, 160)); + maxCntLbl.setLayoutData(UIUtil.formData(null, -1, xlogIgnoreTxt, 5, null, -1, null, -1, 160)); xlogMxCntTxt = new Text(layoutGroup, SWT.BORDER); xlogMxCntTxt.setText(Integer.toString(xLogMaxCount)); - xlogMxCntTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, xlogIgnoreTxt, 8, 100, -5, null, -1, 150)); + xlogMxCntTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, xlogIgnoreTxt, 3, 100, -5, null, -1, 150)); xlogMxCntTxt.addVerifyListener(verifyListener); Label maxDragCntLbl = new Label(layoutGroup, SWT.RIGHT); maxDragCntLbl.setText(M.PREFERENCE_CHARTXLOG_MAX_DRAG_COUNT); - maxDragCntLbl.setLayoutData(UIUtil.formData(null, -1, xlogMxCntTxt, 10, null, -1, null, -1, 160)); + maxDragCntLbl.setLayoutData(UIUtil.formData(null, -1, xlogMxCntTxt, 5, null, -1, null, -1, 160)); xlogMxDragCntTxt = new Text(layoutGroup, SWT.BORDER); xlogMxDragCntTxt.setText(Integer.toString(xLogDragMaxCount)); - xlogMxDragCntTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, xlogMxCntTxt, 8, 100, -5, null, -1, 150)); + xlogMxDragCntTxt.setLayoutData(UIUtil.formData(ignoreLbl, 10, xlogMxCntTxt, 3, 100, -5, null, -1, 150)); xlogMxDragCntTxt.addVerifyListener(verifyListener); + + //XLog column + final Group layoutGroup2 = new Group(parent, SWT.NONE); + layoutGroup2.setText("XLog Columns"); + + layoutGroup2.setLayout(UIUtil.formLayout(5, 5)); + GridData gdata2 = new GridData(); + gdata2.horizontalAlignment = SWT.FILL; + layoutGroup2.setLayoutData(gdata2); + + boolean isFirstCol = true; + Label prevLabel = null; + for (XLogColumnEnum xLogColumn : XLogColumnEnum.values()) { + Label label = new Label(layoutGroup2, SWT.RIGHT); + label.setText(xLogColumn.getTitle() + " :"); + label.setLayoutData(UIUtil.formData(null, -1, isFirstCol ? 0 : prevLabel, 1, null, -1, null, -1, 160)); + + Button button = new Button(layoutGroup2, SWT.CHECK); + button.setSelection(xLogColumnVisibleMap.get(xLogColumn)); + button.setLayoutData(UIUtil.formData(label, 10, isFirstCol ? 0 : prevLabel, -1, 100, -5, null, -1)); + xLogColumnCheckButtonMap.put(xLogColumn, button); + + prevLabel = label; + isFirstCol = false; + } return super.createContents(parent); } @@ -116,6 +141,10 @@ public void init(IWorkbench workbench) { xLogIgnoreTime = PManager.getInstance().getInt(PreferenceConstants.P_XLOG_IGNORE_TIME); xLogMaxCount = PManager.getInstance().getInt(PreferenceConstants.P_XLOG_MAX_COUNT); xLogDragMaxCount = PManager.getInstance().getInt(PreferenceConstants.P_XLOG_DRAG_MAX_COUNT); + + for (XLogColumnEnum xLogColumnEnum : XLogColumnEnum.values()) { + xLogColumnVisibleMap.put(xLogColumnEnum, PManager.getInstance().getBoolean(xLogColumnEnum.getInternalID())); + } } public boolean performOk() { @@ -123,6 +152,11 @@ public boolean performOk() { PManager.getInstance().setValue(PreferenceConstants.P_XLOG_IGNORE_TIME, CastUtil.cint(xlogIgnoreTxt.getText())); PManager.getInstance().setValue(PreferenceConstants.P_XLOG_MAX_COUNT, CastUtil.cint(xlogMxCntTxt.getText())); PManager.getInstance().setValue(PreferenceConstants.P_XLOG_DRAG_MAX_COUNT, CastUtil.cint(xlogMxDragCntTxt.getText())); + + for (XLogColumnEnum xLogColumnEnum : XLogColumnEnum.values()) { + PManager.getInstance().setValue(xLogColumnEnum.getInternalID(), xLogColumnCheckButtonMap.get(xLogColumnEnum).getSelection()); + } + return true; } diff --git a/scouter.client/src/scouter/client/preferences/PManager.java b/scouter.client/src/scouter/client/preferences/PManager.java index c6bf45b98..5acdb59c1 100644 --- a/scouter.client/src/scouter/client/preferences/PManager.java +++ b/scouter.client/src/scouter/client/preferences/PManager.java @@ -18,8 +18,8 @@ package scouter.client.preferences; import org.eclipse.jface.preference.IPreferenceStore; - import scouter.client.Activator; +import scouter.client.xlog.views.XLogColumnEnum; import scouter.lang.counters.CounterConstants; public class PManager { @@ -49,7 +49,11 @@ private PManager() { store.setDefault(PreferenceConstants.P_PERS_WAS_SERV_DEFAULT_DB, CounterConstants.MARIA_DB); store.setDefault(PreferenceConstants.P_MASS_PROFILE_BLOCK, 10); - + + for (XLogColumnEnum xLogColumnEnum : XLogColumnEnum.values()) { + store.setDefault(xLogColumnEnum.getInternalID(), xLogColumnEnum.isDefaultVisible()); + } + // store.setDefault(PreferenceConstants.P_UPDATE_SERVER_ADDR, PORT_AND_REPOSITORY_FOLDER); // store.setDefault(PreferenceConstants.P_ALERT_DIALOG_TIMEOUT, -1); // store.setDefault(PreferenceConstants.NOTIFY_FATAL_ALERT, true); @@ -78,11 +82,13 @@ public String getString(String key){ return store.getString(key); } - public void setDefault(String key, String value){ store.setDefault(key, value); } + public void setDefault(String key, boolean value){ + store.setDefault(key, value); + } public void setValue(String key, boolean value){ store.setValue(key, value); diff --git a/scouter.client/src/scouter/client/xlog/views/XLogColumnEnum.java b/scouter.client/src/scouter/client/xlog/views/XLogColumnEnum.java new file mode 100644 index 000000000..c99d823f2 --- /dev/null +++ b/scouter.client/src/scouter/client/xlog/views/XLogColumnEnum.java @@ -0,0 +1,101 @@ +package scouter.client.xlog.views; + +import org.eclipse.swt.SWT; + +import java.io.Serializable; + +/** + * @author Gun Lee (gunlee01@gmail.com) on 2017. 8. 15. + */ +public enum XLogColumnEnum implements Serializable { + OBJECT("Object", 80, SWT.LEFT, true, true, false, true, "XLOG_COL_OBJECT"), + ELAPSED("Elapsed", 50, SWT.RIGHT, true, true, true, true, "XLOG_COL_ELAPSED"), + SERVICE("Service", 100, SWT.LEFT, true, true, false, true, "XLOG_COL_SERVICE"), + END_TIME("EndTime", 70, SWT.CENTER, true, true, true, true, "XLOG_COL_END_TIME"), + CPU("Cpu", 40, SWT.RIGHT, true, true, true, true, "XLOG_COL_CPU"), + SQL_COUNT("SQL Count", 50, SWT.RIGHT, true, true, true, true, "XLOG_COL_SQL_COUNT"), + SQL_TIME("SQL Time", 50, SWT.RIGHT, true, true, true, true, "XLOG_COL_SQL_TIME"), + KBYTES("KBytes", 60, SWT.RIGHT, true, true, true, true, "XLOG_COL_KBYTES"), + IP("IP", 90, SWT.LEFT, true, true, false, true, "XLOG_COL_IP"), + LOGIN("Login", 50, SWT.LEFT, true, true, false, true, "XLOG_COL_LOGIN"), + DESC("Desc", 50, SWT.LEFT, true, true, false, true, "XLOG_COL_DESC"), + TEXT1("Text1", 50, SWT.LEFT, true, true, false, true, "XLOG_COL_TEXT1"), + TEXT2("Text2", 50, SWT.LEFT, true, true, false, true, "XLOG_COL_TEXT2"), + ERROR("Error", 50, SWT.LEFT, true, true, false, true, "XLOG_COL_ERROR"), + DUMP("Dump", 40, SWT.CENTER, true, true, false, true, "XLOG_COL_DUMP"), + TX_ID("Txid", 30, SWT.LEFT, true, true, false, true, "XLOG_COL_TX_ID"), + GX_ID("Gxid", 30, SWT.LEFT, true, true, false, true, "XLOG_COL_GX_ID"), + START_TIME("StartTime", 70, SWT.CENTER, true, true, true, true, "XLOG_COL_START_TIME"), + UA("UA", 70, SWT.LEFT, true, true, false, false, "XLOG_COL_UA"), + COUNTRY("Country", 40, SWT.LEFT, true, true, false, false, "XLOG_COL_COUNTRY"), + CITY("City", 40, SWT.LEFT, true, true, false, false, "XLOG_COL_CITY"), + GROUP("Group", 40, SWT.LEFT, true, true, false, false, "GROUP"), + ; + + private final String title; + private int width; + private final int alignment; + private final boolean resizable; + private final boolean moveable; + private final boolean isNumber; + private final boolean defaultVisible; + private final String internalID; + + private static final long serialVersionUID = -1477341833201236951L; + + XLogColumnEnum(String text, int width, int alignment, boolean resizable, boolean moveable, boolean isNumber, boolean defaultVisible, String internalID) { + this.title = text; + this.width = width; + this.alignment = alignment; + this.resizable = resizable; + this.moveable = moveable; + this.isNumber = isNumber; + this.defaultVisible = defaultVisible; + this.internalID = internalID; + } + + public String getTitle(){ + return title; + } + + public int getAlignment(){ + return alignment; + } + + public boolean isResizable(){ + return resizable; + } + + public boolean isMoveable(){ + return moveable; + } + + public int getWidth() { + return width; + } + + public boolean isNumber() { + return this.isNumber; + } + + public void setWidth(int width) { + this.width = width; + } + + public boolean isDefaultVisible() { + return defaultVisible; + } + + public String getInternalID() { + return internalID; + } + + public static XLogColumnEnum findByTitle(String title) { + for (XLogColumnEnum columnEnum : XLogColumnEnum.values()) { + if (columnEnum.getTitle().equals(title)) { + return columnEnum; + } + } + throw new RuntimeException(String.format("[FATAL] Invalid XLogColumn title : <%s>", title)); + } +} diff --git a/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java b/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java index 1b01cd36c..965679818 100644 --- a/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java +++ b/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java @@ -21,14 +21,7 @@ import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ColumnPixelData; -import org.eclipse.jface.viewers.IColorProvider; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.*; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; @@ -38,21 +31,17 @@ import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.*; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.part.ViewPart; import scouter.client.Images; import scouter.client.model.TextProxy; import scouter.client.model.XLogData; +import scouter.client.preferences.PManager; import scouter.client.server.Server; import scouter.client.server.ServerManager; import scouter.client.sorter.TableLabelSorter; -import scouter.client.stack.utils.StringUtils; import scouter.client.util.ClientFileUtil; import scouter.client.util.ColorUtil; import scouter.client.util.ExUtil; @@ -67,7 +56,6 @@ import java.io.Serializable; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.stream.IntStream; @@ -150,28 +138,30 @@ private void createColumns() { && isTheSameXLogColumnEnum(columnStore.getColumns())) { columnStore.getColumns().stream().forEach((column) -> { - createTableViewerColumn(column.getTitle(), column.getWidth(), column.getAlignment(), column.isResizable(), column.isMoveable(), column.isNumber()); - columnList.add(column); + if (PManager.getInstance().getBoolean(column.getInternalID())) { + createTableViewerColumn(column.getTitle(), column.getWidth(), column.getAlignment(), column.isResizable(), column.isMoveable(), column.isNumber()); + columnList.add(column); + } }); - } else { for (XLogColumnEnum column : XLogColumnEnum.values()) { - createTableViewerColumn(column.getTitle(), column.getWidth(), column.getAlignment(), column.isResizable(), column.isMoveable(), column.isNumber()); - columnList.add(column); + if (PManager.getInstance().getBoolean(column.getInternalID())) { + createTableViewerColumn(column.getTitle(), column.getWidth(), column.getAlignment(), column.isResizable(), column.isMoveable(), column.isNumber()); + columnList.add(column); + } } } viewer.setLabelProvider(new TableItemProvider()); } private boolean isTheSameXLogColumnEnum(List loadedColummEnumList) { - if(loadedColummEnumList.size() != XLogColumnEnum.values().length) { - return false; - } - if (loadedColummEnumList.containsAll(new ArrayList<>(Arrays.asList(XLogColumnEnum.values())))) { - return true; - } else { - return false; + for (XLogColumnEnum xLogColumn : XLogColumnEnum.values()) { + boolean visible = PManager.getInstance().getBoolean(xLogColumn.getInternalID()); + if (visible && loadedColummEnumList.contains(xLogColumn) == false) { + return false; + } } + return true; } private void saveColumnsInfo() { @@ -354,87 +344,6 @@ private void copyToClipboard() { } } } - - enum XLogColumnEnum implements Serializable { - OBJECT("Object", 80, SWT.LEFT, true, true, false), - ELAPSED("Elapsed", 50, SWT.RIGHT, true, true, true), - SERVICE("Service", 100, SWT.LEFT, true, true, false), - END_TIME("EndTime", 70, SWT.CENTER, true, true, true), - CPU("Cpu", 40, SWT.RIGHT, true, true, true), - SQL_COUNT("SQL Count", 50, SWT.RIGHT, true, true, true), - SQL_TIME("SQL Time", 50, SWT.RIGHT, true, true, true), - KBYTES("KBytes", 60, SWT.RIGHT, true, true, true), - IP("IP", 90, SWT.LEFT, true, true, false), - LOGIN("Login", 50, SWT.LEFT, true, true, false), - DUMP("Dump", 40, SWT.CENTER, true, true, false), - ERROR("Error", 50, SWT.LEFT, true, true, false), - TX_ID("Txid", 30, SWT.LEFT, true, true, false), - GX_ID("Gxid", 30, SWT.LEFT, true, true, false), - DESC("Desc", 50, SWT.LEFT, true, true, false), - TEXT1("Text1", 50, SWT.LEFT, true, true, false), - TEXT2("Text2", 50, SWT.LEFT, true, true, false), - START_TIME("StartTime", 70, SWT.CENTER, true, true, true), - UA("UA", 70, SWT.LEFT, true, true, false), - COUNTRY("Country", 40, SWT.LEFT, true, true, false), - CITY("City", 40, SWT.LEFT, true, true, false), - GROUP("Group", 40, SWT.LEFT, true, true, false), - ; - - private final String title; - private int width; - private final int alignment; - private final boolean resizable; - private final boolean moveable; - private final boolean isNumber; - - private static final long serialVersionUID = -1477341833201236951L; - - private XLogColumnEnum(String text, int width, int alignment, boolean resizable, boolean moveable, boolean isNumber) { - this.title = text; - this.width = width; - this.alignment = alignment; - this.resizable = resizable; - this.moveable = moveable; - this.isNumber = isNumber; - } - - public String getTitle(){ - return title; - } - - public int getAlignment(){ - return alignment; - } - - public boolean isResizable(){ - return resizable; - } - - public boolean isMoveable(){ - return moveable; - } - - public int getWidth() { - return width; - } - - public boolean isNumber() { - return this.isNumber; - } - - public void setWidth(int width) { - this.width = width; - } - - public static XLogColumnEnum findByTitle(String title) { - for (XLogColumnEnum columnEnum : XLogColumnEnum.values()) { - if (columnEnum.getTitle().equals(title)) { - return columnEnum; - } - } - throw new RuntimeException(String.format("[FATAL] Invalid XLogColumn title : <%s>", title)); - } - } public void dispose() { clipboard.dispose(); diff --git a/scouter.common/src/main/java/scouter/lang/conf/ConfigValueType.java b/scouter.common/src/main/java/scouter/lang/conf/ConfigValueType.java new file mode 100644 index 000000000..76dfc35aa --- /dev/null +++ b/scouter.common/src/main/java/scouter/lang/conf/ConfigValueType.java @@ -0,0 +1,26 @@ +/* + * 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.lang.conf; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface ConfigValueType { + ValueType value() default ValueType.VALUE; +} diff --git a/scouter.common/src/main/java/scouter/lang/conf/ConfigValueUtil.java b/scouter.common/src/main/java/scouter/lang/conf/ConfigValueUtil.java index 5f583f5ba..aa33f7769 100644 --- a/scouter.common/src/main/java/scouter/lang/conf/ConfigValueUtil.java +++ b/scouter.common/src/main/java/scouter/lang/conf/ConfigValueUtil.java @@ -17,13 +17,6 @@ package scouter.lang.conf; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Properties; - import scouter.lang.value.BooleanValue; import scouter.lang.value.DecimalValue; import scouter.lang.value.DoubleValue; @@ -32,10 +25,16 @@ import scouter.lang.value.TextValue; import scouter.lang.value.Value; import scouter.util.ArrayUtil; -import scouter.util.ParamText; import scouter.util.StringKeyLinkedMap; import scouter.util.StringUtil; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + public class ConfigValueUtil { public static Properties replaceSysProp(Properties temp) { Properties p = new Properties(); @@ -92,6 +91,37 @@ public static StringKeyLinkedMap getConfigDescMap(Object o) { return descMap; } + public static StringKeyLinkedMap getConfigValueTypeMap(Object o) { + StringKeyLinkedMap valueTypeMap = new StringKeyLinkedMap(); + Field[] fields = o.getClass().getFields(); + for (int i = 0; i < fields.length; i++) { + int mod = fields[i].getModifiers(); + if (Modifier.isStatic(mod) == false && Modifier.isPublic(mod)) { + try { + ValueType valueType; + Class type = fields[i].getType(); + if (type == Integer.TYPE || type == Long.TYPE + || type.isAssignableFrom(Integer.class) || type.isAssignableFrom(Long.class)) { + valueType = ValueType.NUM; + } else if (type == Boolean.TYPE || type == Boolean.class) { + valueType = ValueType.BOOL; + } else { + valueType = ValueType.VALUE; + } + + ConfigValueType annotation = fields[i].getAnnotation(ConfigValueType.class); + if (annotation != null) { + valueType = annotation.value(); + } + String name = fields[i].getName(); + valueTypeMap.put(name, valueType); + } catch (Exception e) { + } + } + } + return valueTypeMap; + } + public static Value toValue(Object o) { if (o == null) return new NullValue(); @@ -114,4 +144,4 @@ public static Value toValue(Object o) { return new TextValue(o.toString()); } -} \ No newline at end of file +} diff --git a/scouter.common/src/main/java/scouter/lang/conf/ValueType.java b/scouter.common/src/main/java/scouter/lang/conf/ValueType.java new file mode 100644 index 000000000..f49f9527c --- /dev/null +++ b/scouter.common/src/main/java/scouter/lang/conf/ValueType.java @@ -0,0 +1,47 @@ +/* + * 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.lang.conf; + +/** + * Created by gunlee on 2017. 8. 17. + */ +public enum ValueType { + VALUE(1), + NUM(2), + BOOL(3), + COMMA_SEPARATED_VALUE(4), + ; + + int type; + ValueType(int type) { + this.type = type; + } + + public int getType() { + return type; + } + + public static ValueType of(int type) { + ValueType[] values = values(); + for (ValueType value : values) { + if (value.type == type) { + return value; + } + } + return VALUE; + } +} diff --git a/scouter.common/src/main/java/scouter/lang/plugin/PluginConstants.java b/scouter.common/src/main/java/scouter/lang/plugin/PluginConstants.java index cf0b1a8fe..3676a4d31 100644 --- a/scouter.common/src/main/java/scouter/lang/plugin/PluginConstants.java +++ b/scouter.common/src/main/java/scouter/lang/plugin/PluginConstants.java @@ -10,4 +10,5 @@ public class PluginConstants { public static final String PLUGIN_SERVER_SUMMARY = "pluginServerSummary"; public static final String PLUGIN_SERVER_XLOG = "pluginServerXLog"; public static final String PLUGIN_SERVER_PROFILE = "pluginServerProfile"; + public static final String PLUGIN_SERVER_TEXT = "pluginServerText"; } diff --git a/scouter.common/src/main/java/scouter/lang/step/ParameterizedMessageStep.java b/scouter.common/src/main/java/scouter/lang/step/ParameterizedMessageStep.java index 983c4afe1..ee06e524c 100644 --- a/scouter.common/src/main/java/scouter/lang/step/ParameterizedMessageStep.java +++ b/scouter.common/src/main/java/scouter/lang/step/ParameterizedMessageStep.java @@ -110,7 +110,7 @@ public String buildMessasge(String messageFormat) { return messageFormat; } - return String.format(messageFormat, params); + return String.format(messageFormat, (Object[])params); } catch (Exception e) { return messageFormat; } diff --git a/scouter.common/src/main/java/scouter/net/RequestCmd.java b/scouter.common/src/main/java/scouter/net/RequestCmd.java index 5af8347ff..fb2476098 100644 --- a/scouter.common/src/main/java/scouter/net/RequestCmd.java +++ b/scouter.common/src/main/java/scouter/net/RequestCmd.java @@ -165,6 +165,7 @@ public class RequestCmd { public static final String LIST_CONFIGURE_WAS = "LIST_CONFIGURE_WAS"; public static final String REDEFINE_CLASSES = "REDEFINE_CLASSES"; public static final String CONFIGURE_DESC = "CONFIGURE_DESC"; + public static final String CONFIGURE_VALUE_TYPE = "CONFIGURE_VALUE_TYPE"; public static final String GET_XML_COUNTER = "GET_XML_COUNTER"; @@ -289,4 +290,4 @@ public static boolean isFreeCmd(String cmd) { return freeCmdSet.contains(cmd); } -} \ No newline at end of file +} diff --git a/scouter.document/main/Alert-Plugin-Guide.md b/scouter.document/main/Alert-Plugin-Guide.md index 131339506..648b4d3f1 100644 --- a/scouter.document/main/Alert-Plugin-Guide.md +++ b/scouter.document/main/Alert-Plugin-Guide.md @@ -25,94 +25,89 @@ We can build our own alarm rules by handling alert scripting plugins which are a * sample1 (**GcTime.alert**) * alert when ```GcTime``` is over than 2 sec ```java - // void process(RealCounter $counter) + // void process(RealCounter $counter, PluginHelper $$) int gcTime = $counter.intValue(); if(gcTime > 2000) { $counter.fatal("gc time fatal", "gc time:" + respTime + "ms"); } ``` - + * sample2 (**Elasped90%.alert**) * alert when ```Elasped90%``` is over than 1.5 sec (ignore when TPS is lower than 3 sec.) ```java - // void process(RealCounter $counter) + // void process(RealCounter $counter, PluginHelper $$) int warn = 1500; int fatal = 2000; - + int tps = $counter.intValue("TPS"); int respTime = $counter.intValue(); - + String objType = $counter.objType(); String objName = $counter.objName(); - - java.text.NumberFormat f = java.text.NumberFormat.getInstance(); - f.setMaximumFractionDigits(2); - + if(tps < 3) return; if(respTime > fatal) { - $counter.fatal("resp time fatal high", "90% resp time:" + f.format((long)respTime) + "ms, tps:" + tps); + $counter.fatal("resp time fatal high", "90% resp time:" + $$.formatNumber(respTime) + "ms, tps:" + tps); } else if(respTime > warn) { - $counter.warn("resp time warn high", "90% resp time:" + f.format((long)respTime) + "ms, tps:" + tps); + $counter.warn("resp time warn high", "90% resp time:" + $$.formatNumber(respTime) + "ms, tps:" + tps); } ``` - + * sample3 (**TPS.alert**) - * alert when ```TPS``` increase or decrease sharply. + * alert when ```TPS``` increase or decrease sharply. ```java - // void process(RealCounter $counter) - - //increase + // void process(RealCounter $counter, PluginHelper $$) + + //increase float initTps = 20.0; float warnIncreaseRate = 1.2; float fatalIncreaseRate = 1.5; int compareBeforeSec = 180; - + //decrease - float fatal1DecreaseRate = 0.7; //30% - float fatal2DecreaseRate = 0.5; //50% + float fatal1DecreaseRate = 0.7; //30% + float fatal2DecreaseRate = 0.5; //50% int compareBeforeDecreaseSec = 120; //last 2 minute - + float tps = $counter.floatValue(); String objType = $counter.objType(); String objName = $counter.objName(); float errorRate = $counter.floatValue(); - java.text.NumberFormat f = java.text.NumberFormat.getInstance(); - f.setMaximumFractionDigits(1); - + if(tps > initTps) { float preValue = $counter.getAvg(compareBeforeSec, 4); if(preValue > 0.0f) { if(tps > preValue * fatalIncreaseRate) { $counter.fatal("TPS increase fatal" - , "TPS is " + f.format((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + , "TPS is " + $$.formatNumber((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + ", TPS: " + tps); - + } else if(tps > preValue * warnIncreaseRate) { $counter.warn("TPS increase warning" - , "TPS is " + f.format((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + , "TPS is " + $$.formatNumber((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + ", TPS: " + tps); } } } - + float preValue = $counter.getAvg(compareBeforeDecreaseSec, 4); if(preValue > 5.0f) { if(tps < preValue * fatal2DecreaseRate) { $counter.fatal("TPS decrease fatal" - , "TPS is " + f.format(((double)1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + , "TPS is " + $$.formatNumber(((double)1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + ", TPS: " + tps); } else if(tps < preValue * fatal1DecreaseRate) { $counter.error("TPS decrease warn" - , "TPS is " + f.format((double)(1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + , "TPS is " + $$.formatNumber((double)(1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + ", TPS: " + tps); } } - ``` - -### RealCounter API + ``` + +### RealCounter API | method | desc | | ------------ | ---------- | -| objName() | get object's name that produced the counter value | +| objName() | get object's name that produced the counter value | | objType() | get object's type that produced the counter value | | intValue() | get counter value as integer | | floatValue() | get counter value as float | @@ -131,3 +126,5 @@ We can build our own alarm rules by handling alert scripting plugins which are a ### Counter names * [counters.xml](https://github.com/scouter-project/scouter/blob/fe74bdb73a34be2f390f8476991d59a5de6ea204/scouter.common/src/main/resources/scouter/lang/counters/counters.xml) +### $$ (PluginHelper) API + - Refer to **[PluginHelper API](./PluginHelper-API.md)** \ No newline at end of file diff --git a/scouter.document/main/Alert-Plugin-Guide_kr.md b/scouter.document/main/Alert-Plugin-Guide_kr.md index 886ce1b95..9fa5a3ee4 100644 --- a/scouter.document/main/Alert-Plugin-Guide_kr.md +++ b/scouter.document/main/Alert-Plugin-Guide_kr.md @@ -25,7 +25,7 @@ We can build our own alarm rules by handling alert scripting plugins which are a * sample1 (**GcTime.alert**) * alert when ```GcTime``` is over than 2 sec ```java - // void process(RealCounter $counter) + // void process(RealCounter $counter, PluginHelper $$) int gcTime = $counter.intValue(); if(gcTime > 2000) { $counter.fatal("gc time fatal", "gc time:" + respTime + "ms"); @@ -35,7 +35,7 @@ We can build our own alarm rules by handling alert scripting plugins which are a * sample2 (**Elasped90%.alert**) * alert when ```Elasped90%``` is over than 1.5 sec (ignore when TPS is lower than 3 sec.) ```java - // void process(RealCounter $counter) + // void process(RealCounter $counter, PluginHelper $$) int warn = 1500; int fatal = 2000; @@ -45,21 +45,18 @@ We can build our own alarm rules by handling alert scripting plugins which are a String objType = $counter.objType(); String objName = $counter.objName(); - java.text.NumberFormat f = java.text.NumberFormat.getInstance(); - f.setMaximumFractionDigits(2); - if(tps < 3) return; if(respTime > fatal) { - $counter.fatal("resp time fatal high", "90% resp time:" + f.format((long)respTime) + "ms, tps:" + tps); + $counter.fatal("resp time fatal high", "90% resp time:" + $$.formatNumber(respTime) + "ms, tps:" + tps); } else if(respTime > warn) { - $counter.warn("resp time warn high", "90% resp time:" + f.format((long)respTime) + "ms, tps:" + tps); + $counter.warn("resp time warn high", "90% resp time:" + $$.formatNumber(respTime) + "ms, tps:" + tps); } ``` * sample3 (**TPS.alert**) * alert when ```TPS``` increase or decrease sharply. ```java - // void process(RealCounter $counter) + // void process(RealCounter $counter, PluginHelper $$) //increase float initTps = 20.0; @@ -76,20 +73,18 @@ We can build our own alarm rules by handling alert scripting plugins which are a String objType = $counter.objType(); String objName = $counter.objName(); float errorRate = $counter.floatValue(); - java.text.NumberFormat f = java.text.NumberFormat.getInstance(); - f.setMaximumFractionDigits(1); - + if(tps > initTps) { float preValue = $counter.getAvg(compareBeforeSec, 4); if(preValue > 0.0f) { if(tps > preValue * fatalIncreaseRate) { $counter.fatal("TPS increase fatal" - , "TPS is " + f.format((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + , "TPS is " + $$.formatNumber((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + ", TPS: " + tps); } else if(tps > preValue * warnIncreaseRate) { $counter.warn("TPS increase warning" - , "TPS is " + f.format((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + , "TPS is " + $$.formatNumber((double)tps/preValue*100) + "% higher than " + compareBeforeSec + "sec ago" + ", TPS: " + tps); } } @@ -99,11 +94,11 @@ We can build our own alarm rules by handling alert scripting plugins which are a if(preValue > 5.0f) { if(tps < preValue * fatal2DecreaseRate) { $counter.fatal("TPS decrease fatal" - , "TPS is " + f.format(((double)1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + , "TPS is " + $$.formatNumber(((double)1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + ", TPS: " + tps); } else if(tps < preValue * fatal1DecreaseRate) { $counter.error("TPS decrease warn" - , "TPS is " + f.format((double)(1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + , "TPS is " + $$.formatNumber((double)(1-tps/preValue)*100) + "% lower than " + compareBeforeDecreaseSec + "sec ago" + ", TPS: " + tps); } } @@ -131,3 +126,5 @@ We can build our own alarm rules by handling alert scripting plugins which are a ### Counter names * [counters.xml](https://github.com/scouter-project/scouter/blob/fe74bdb73a34be2f390f8476991d59a5de6ea204/scouter.common/src/main/resources/scouter/lang/counters/counters.xml) +### $$ (PluginHelper) API + - Refer to **[PluginHelper API](./PluginHelper-API.md)** \ No newline at end of file diff --git a/scouter.document/main/Configuration.md b/scouter.document/main/Configuration.md index f62b789ce..99ca2e233 100644 --- a/scouter.document/main/Configuration.md +++ b/scouter.document/main/Configuration.md @@ -40,15 +40,19 @@ public int net_tcp_listen_port = 6100; @ConfigDesc("Http Port for scouter-pulse") public int net_http_port = 6180; -//Manager +//Management @ConfigDesc("Activating automatic deletion function in the database") public boolean mgr_purge_enabled = true; -@ConfigDesc("Automatic deletion only for XLog data") -public boolean mgr_purge_only_xlog_enabled = false; -@ConfigDesc("Condition of disc usage for automatic deletion") + +@ConfigDesc("Condition of disk usage for automatic deletion. if lack, delete profile data first exclude today data.") public int mgr_purge_disk_usage_pct = 80; + +@ConfigDesc("Retaining date for automatic deletion. delete profile data first.") +public int mgr_purge_profile_keep_days = 10; +@ConfigDesc("Retaining date for automatic deletion.") +public int mgr_purge_xlog_keep_days = 30; @ConfigDesc("Retaining date for automatic deletion") -public int mgr_purge_keep_days = 0; +public int mgr_purge_counter_keep_days = 70; //GeoIP @ConfigDesc("Activating IP-based city/country extraction") @@ -81,7 +85,7 @@ public int net_collector_udp_port = 6100; @ConfigDesc("Collector TCP Port") public int net_collector_tcp_port = 6100; -@ConfigDesc("Activating SQL literals") +@ConfigDesc("Escaping literal parameters for normalizing the query") public boolean profile_sql_escape_enabled = true; //Naming / grouping diff --git a/scouter.document/main/Configuration_kr.md b/scouter.document/main/Configuration_kr.md index 7d698c934..05b5199a0 100644 --- a/scouter.document/main/Configuration_kr.md +++ b/scouter.document/main/Configuration_kr.md @@ -40,15 +40,19 @@ public int net_tcp_listen_port = 6100; @ConfigDesc("Http Port for scouter-pulse") public int net_http_port = 6180; -//Manager +//Management @ConfigDesc("Activating automatic deletion function in the database") public boolean mgr_purge_enabled = true; -@ConfigDesc("Automatic deletion only for XLog data") -public boolean mgr_purge_only_xlog_enabled = false; -@ConfigDesc("Condition of disc usage for automatic deletion") + +@ConfigDesc("Condition of disk usage for automatic deletion. if lack, delete profile data first exclude today data.") public int mgr_purge_disk_usage_pct = 80; + +@ConfigDesc("Retaining date for automatic deletion. delete profile data first.") +public int mgr_purge_profile_keep_days = 10; +@ConfigDesc("Retaining date for automatic deletion.") +public int mgr_purge_xlog_keep_days = 30; @ConfigDesc("Retaining date for automatic deletion") -public int mgr_purge_keep_days = 0; +public int mgr_purge_counter_keep_days = 70; //GeoIP @ConfigDesc("Activating IP-based city/country extraction") @@ -81,7 +85,7 @@ public int net_collector_udp_port = 6100; @ConfigDesc("Collector TCP Port") public int net_collector_tcp_port = 6100; -@ConfigDesc("Activating SQL literals") +@ConfigDesc("Escaping literal parameters for normalizing the query") public boolean profile_sql_escape_enabled = true; //Naming / grouping diff --git a/scouter.document/main/Getting-Start-Profile-SQL_kr.md b/scouter.document/main/Getting-Start-Profile-SQL_kr.md index 52c2d479b..4602c4462 100644 --- a/scouter.document/main/Getting-Start-Profile-SQL_kr.md +++ b/scouter.document/main/Getting-Start-Profile-SQL_kr.md @@ -3,7 +3,7 @@ > 본문서에서는 HSQL DB를 설치하고 간단한 샘플 애플리케이션을 실행하여 > SQL이 어떤식으로 모니터링 되는지 설명한다. -> 본문서는 이미 [Getting Started](./Getting-Started_kr.md)를 이해한다는 전제로 설명한다. +> 본문서는 이미 [Getting Started](./Getting-Stzarted_kr.md)를 이해한다는 전제로 설명한다. ## HSQL설치하기 diff --git a/scouter.document/main/JavaAgent-Plugin-Scripting.md b/scouter.document/main/JavaAgent-Plugin-Scripting.md index 46a7104cf..e7d01520a 100644 --- a/scouter.document/main/JavaAgent-Plugin-Scripting.md +++ b/scouter.document/main/JavaAgent-Plugin-Scripting.md @@ -2,140 +2,143 @@ ![English](https://img.shields.io/badge/language-English-orange.svg) [![Korean](https://img.shields.io/badge/language-Korean-blue.svg)](JavaAgent-Plugin-Scripting_kr.md) ## Javaagent Plugin - - Default File Location : ${directory of scouter.agent.jar}/plugin - - or able to configure it for example - plugin_dir=/aaa/bbb/ccc/plugin + - Default File Location : ```${directory of scouter.agent.jar}/plugin``` + - or able to configure it for example - ```plugin_dir=/aaa/bbb/ccc/plugin``` - Write java code on the specific text file then the code is dynamically loaded on runtime. - - Plugin 종류 - - Http-service - - Service - - HttpCall - - Capture - - JDBC-Pool + - plugin types + - Http-service plugin + - Service plugin + - HttpCall plugin + - Capture plugin + - JDBC-Pool plugin ### Http-service Plugin(httpservice.plug) -1. void start(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점 -2. void end(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 종료 시점 -3. boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점에 reject 조건 (default : false) +1. ```void start(WrContext $ctx, WrRequest $req, WrResponse $res)``` : invoked at the start of HttpServlet service() method +2. ```void end(WrContext $ctx, WrRequest $req, WrResponse $res)``` : invoked at the end of HttpServlet service() method +3. ```boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res)``` : invoked at the start of HttpServlet service() method. If return true then the request is rejected ### Service Plugin(service.plug) - **추가적인 hooking 설정을 통해서만 동작** + **invoked when arrived the methods defined in the option ```hook_service_patterns```** -1. void start(WrContext $ctx, HookArgs $hook) : Service 시작 시점 -2. void end(WrContext $ctx) : Service 종료 시점 +1. ```void start(WrContext $ctx, HookArgs $hook)``` : invoked when a service starts +2. ```void end(WrContext $ctx)``` : invoked when a service ends ### HttpCall Plugin(httpcall.plug) -1. void call(WrContext $ctx, WrHttpCallRequest $req) : Http Call 요청 시점 +1. ```void call(WrContext $ctx, WrHttpCallRequest $req)``` : invoked when an external call is invoked by httpClient and http client libraries. ### Capture Plugin(capture.plug) - **추가적인 hooking 설정을 통해서만 동작** + **invoked when arrived the methods defined in the options ```hook_args_patterns```, ```hook_return_patterns``` and ```hook_constructor_patterns```** -1. void capArgs(WrContext $ctx, HookArgs $hook) : Method 시작 시점 -2. void capReturn(WrContext $ctx, HookReturn $hook) : Method Return 시점 -3. void capThis(WrContext $ctx, String $class, String $desc, Object $this) : Constructor 생성 시점 +1. ```void capArgs(WrContext $ctx, HookArgs $hook)``` : invoked at the start of the method +2. ```void capReturn(WrContext $ctx, HookReturn $hook)``` : invoked at the end of the method +3. ```void capThis(WrContext $ctx, String $class, String $desc, Object $this)``` : invoked at a constructor ### JDBC-Pool Plugin(jdbcpool.plug) - -1. String url(WrContext $ctx, String $msg, Object $pool) - : DB Connection URL 요청 시점 +1. ```String url(WrContext $ctx, String $msg, Object $pool)``` + : invoked when retrieve DB Connection URL ## API ### Common API - - void log(Object c) : Logger를 통한 log - - void println(Object c) : System.out를 통한 log - - Object field(Object o, String field) : Object의 filed 값을 가져옴 - - Object method(Object o, String method) : Object의 method를 강제invoke 함 - - Object method1(Object o, String method) : Object의 method를 invoke 함 - - Object method(Object o, String method, String param) : Object의 method를 String 파라미터와 함께 invoke 함 - - String toString(Object o) : Object 를 toString 하여 반환 - - String toString(Object o, String def) : Object 를 toString 하여 반환, null 이면 default string 반환 - - void alert(char level, String title, String message) : Alert 을 보냄 - - int syshash(Object o) : Object 의 identityHash 값 반환 - - int syshash(HookArgs hook, int x) : Arguments의 i 인덱스의 identyHash 값 반환 - - int syshash(HookArgs hook) : This 의 identyHash 값 반환 - - void forward(WrContext wctx, int uuid) : Async Thread 를 App service로 연결 - - void forwardThread(WrContext wctx, int uuid) : Async Thread 를 Background service로 연결 - - void receive(WrContext ctx, int uuid) : 앞서 등록된 Service가 있으면 연결 - + - ```void log(Object c)``` : logging + - ```void println(Object c)``` : System.out.println() + - ```Object getFieldValue(Object o, String fieldName)``` : get field value as object of 'o' + - ```Object invokeMethod(Object o, String methodName)``` : invoke the method + - ```Object invokeMethod(Object o, String methodName, Object[] args)``` : invoke the method with args + - ```Object invokeMethod(Object o, String methodName, Class[] argTypes, Object[] args)``` : invoke the method with args + - ```Object newInstance(String className)``` : new instance of the class + - ```Object newInstance(String className, ClassLoader loader)``` : new instance of the class from the classloader + - ```Object newInstance(String className, Object[] args)``` : new instance of the class with arguments + - ```Object newInstance(String className, ClassLoader loader, Object[] args)``` : new instance of the class with arguments from the classloader + - ```Object newInstance(String className, ClassLoader loader, Class[] argTypes, Object[] args)``` : new instance of the class with arguments from the classloader + - ```String toString(Object o)``` : invoke toString() of the object + - ```String toString(Object o, String def)``` : invoke toString() of the object, if null, return def. + - ```void alert(char level, String title, String message)``` : invoke alert (level : i\|w\|e\|f as info, warn, error, fatal). + - ```Class[] makeArgTypes(Class class0, Class class1, ..., classN)``` : assemble argument types array to call the reflection method ```invokeMethod()``` + - ```Object[] makeArgs(Object obj0, Object obj1, ..., objN)``` : assemble arguments array to call the reflection method ```invokeMethod()``` ### WrContext class API - - String service() : Service Name 을 반환 - - void service(String name) : Service Name 을 set - - int serviceHash() : Service Hash 값을 반환 - - void remoteIp(String ip) : Remote IP 을 set - - String remoteIp() : Remote IP를 반환 - - void error(String err) : 임의의 error 를 주입 - - boolean isError() : 에러 체크 - - void group(String group) : 임의의 group을 set - - String group() : Group을 반환 - - void login(String id) : 임의의 사용자 ID 를 set - - String login() : 사용자 ID를 반환 - - void desc(String desc) : 임의의 Desc를 set - - String desc() : Desc를 반환 - - String httpMethod() : Http Method를 반환 - - String httpQuery() : Http Query를 반환 - - String httpContentType() : Http Content-type을 반환 - - String userAgent() : User-Agent를 반환 - - void profile(String msg) : Msg 를 profile에 기록 - - long txid() : txid 를 반환 - - long gxid() : gxid 를 반환 - - TraceContext inner() : context를 반환 + - ```String service()``` : get a service name of XLog from the trace context + - ```void service(String name)``` : set a service Name of XLog to the trace context + - ```int serviceHash()``` : get a service hash value of XLog from the trace context + - ```void remoteIp(String ip)``` : set a remote ip of XLog to the trace context + - ```String remoteIp()``` : get a remote ip of XLog from the trace context + - ```void error(String err)``` : set a error message of XLog to the trace context + - ```boolean isError()``` : if error occurred in the trace context + - ```void group(String group)``` : set a group name of XLog to the trace context + - ```String group()``` : get a group name of XLog from the trace context + - ```void login(String id)``` : set a login value of XLog to the trace context + - ```String login()``` : get a login value of XLog from the trace context + - ```void desc(String desc)``` : set a desc value of XLog to the trace context + - ```String desc()``` : get a desc value of XLog from the trace context + - ```String httpMethod()``` : get a http method + - ```String httpQuery()``` : get a http query string + - ```String httpContentType()``` : get a http content type + - ```String userAgent()``` : get a user agent value + - ```void profile(String msg)``` : profile a message to the XLog profile + - ```void hashProfile(String msg, int value, int elapsed)``` : profile a message as hash value to the XLog profile + - ```parameterizedProfile(int level, String msgFormat, int elapsed, String[] params)``` : profile a message format with parameters. + - message example : "Hello, my name is %s and my age is %s" + - level : 0-debug, 1-info, 2-warn, 3-error, 4-fatal + - ```long txid()``` : get a txid of XLog + - ```long gxid()``` : get a gxid of XLog + - ```TraceContext inner()``` : get raw TraceContext를 반환 ### WrRequest class API - - String getCookie(String key) : Cookie 값을 반환 - - String getRequestURI() : Request URI를 반환 - - String getRemoteAddr() : Remote Address를 반환 - - String getMethod() : Method 를 반환 - - String getQueryString() : Query String을 반환 - - String getParameter(String key) : Parameter를 반환 - - Object getAttribute(String key) : Attribute를 반환 - - String getHeader(String key) : Header값을 반환 - - Enumeration getParameterNames() : Parameter 값들을 반환 - - Enumeration getHeaderNames() : HeaderName들을 반환 - - WrSession getSession() : WrSession객체를 반환 - - Set getSessionNames() : Session Name들을 반환 - - Object getSessionAttribute(String key) : Session 값을 반환 - - Object inner() : Request Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```String getCookie(String key)``` : get a cookie of the key from the HttpRequest + - ```String getRequestURI()``` : get a request uri from the HttpRequest + - ```String getRemoteAddr()``` : get a remote address from the HttpRequest + - ```String getMethod()``` : get a http method from the HttpRequest + - ```String getQueryString()``` : get a query string from the HttpRequest + - ```String getParameter(String key)``` : get a http parameter of the key from the HttpRequest + - ```Object getAttribute(String key)``` : get a http request attribute of the key from the HttpRequest + - ```String getHeader(String key)``` : get a http header of the key from the HttpRequest + - ```Enumeration getParameterNames()``` : + - ```Enumeration getHeaderNames()``` : + - ```WrSession getSession()``` : get the WrSession instance + - ```Set getSessionNames()``` : get session attribute names from the HttpRequest + - ```Object getSessionAttribute(String key)``` : get a session value of the key + - ```Object inner()``` : get the raw HttpRequest object + - ```boolean isOk()``` : check the plugin status + - ```Throwable error()``` : get the error that occurred when the WrRequest method called. ### WrResponse class API - - PrintWriter getWriter() : Writer를 반환 - - String getContentType() : Content-type을 반환 - - String getCharacterEncoding() : Character-encoding을 반환 - - Object inner() : Response Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```PrintWriter getWriter()``` : get the response writer + - ```String getContentType()``` : get a content type of the response + - ```String getCharacterEncoding()``` : get a encoding of the response + - ```Object inner()``` : get the raw Response object + - ```boolean isOk()``` : check the plugin status + - ```Throwable error()``` : get the error that occurred when the WrResponse method called. ### WrSession class API - - getAttribute(String key) : Attribute를 반환 - - Enumeration getAttributeNames() : Attribute Names를 반환 - - Object inner() : Session Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```Object getAttribute(String key)``` : + - ```Enumeration getAttributeNames()``` : + - ```Object inner()``` : get the raw HttpSession object + - ```boolean isOk()``` : check the plugin status + - ```Throwable error()``` : get the error that occurred when the WrResponse method called. ### WrHttpCallRequest class API - - void header(Object key, Object value) : Header값 추가 - - Object inner() : Request Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```void header(Object key, Object value)``` : add http header before the call invoked + - ```Object inner()``` : get the http call object + - ```boolean isOk()``` : check the plugin status + - ```Throwable error()``` : get the error that occurred when the WrResponse method called. ### HookArgs class API - - String getClassName() : Class 이름 반환 - - String getMethodName() : Method 이름 반환 - - String getMethodDesc() : Method 의 Desc 반환 - - Object getThis() : this object 반환 - - Object[] getArgs() : Arguments 반환 - - int getArgCount() : Argument 갯수 반환 + - ```String getClassName()``` : get the class name of the invoked method + - ```String getMethodName()``` : get the method name invoked + - ```String getMethodDesc()``` : get the method description + - ```Object getThis()``` : get this + - ```Object[] getArgs()``` : get the method arguments + - ```int getArgCount()``` : get the argument count ### HookReturn class API - - String getClassName() : Class 이름 반환 - - String getMethodName() : Method 이름 반환 - - String getMethodDesc() : Method 의 Desc 반환 - - Object getThis() : this object 반환 - - Object getReturn() : Return 값 반환 + - ```String getClassName()``` : get the class name of the invoked method + - ```String getMethodName()``` : get the method name invoked + - ```String getMethodDesc()``` : get the method description + - ```Object getThis()``` : get this + - ```Object getReturn()``` : get a return value diff --git a/scouter.document/main/JavaAgent-Plugin-Scripting_kr.md b/scouter.document/main/JavaAgent-Plugin-Scripting_kr.md index aa9cfa7ae..245d5b2b8 100644 --- a/scouter.document/main/JavaAgent-Plugin-Scripting_kr.md +++ b/scouter.document/main/JavaAgent-Plugin-Scripting_kr.md @@ -2,8 +2,8 @@ [![English](https://img.shields.io/badge/language-English-orange.svg)](JavaAgent-Plugin-Scripting.md) ![Korean](https://img.shields.io/badge/language-Korean-blue.svg) ## Javaagent Plugin - - Default File Location : ${directory of scouter.agent.jar}/plugin - - 또는 설정 가능 -> plugin_dir=/aaa/bbb/ccc/plugin + - Default File Location : ```${directory of scouter.agent.jar}/plugin``` + - 또는 설정 가능 -> ```plugin_dir=/aaa/bbb/ccc/plugin``` - plugin 파일에 java 코드 기록시 런타임에 동적으로 코드를 컴파일하여 로딩, 바로 적용됨 - Plugin 종류 - Http-service @@ -14,128 +14,133 @@ ### Http-service Plugin(httpservice.plug) -1. void start(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점 -2. void end(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 종료 시점 -3. boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res) : Http Service 시작 시점에 reject 조건 (default : false) +1. ```void start(WrContext $ctx, WrRequest $req, WrResponse $res)``` : Http Service 시작 시점 +2. ```void end(WrContext $ctx, WrRequest $req, WrResponse $res)``` : Http Service 종료 시점 +3. ```boolean reject(WrContext $ctx, WrRequest $req, WrResponse $res)``` : Http Service 시작 시점에 reject 조건 (default : false) ### Service Plugin(service.plug) - **추가적인 hooking 설정을 통해서만 동작** + **```hook_service_patterns``` 에 정의된 method 에서 호출됨** -1. void start(WrContext $ctx, HookArgs $hook) : Service 시작 시점 -2. void end(WrContext $ctx) : Service 종료 시점 +1. ```void start(WrContext $ctx, HookArgs $hook)``` : Service 시작 시점 +2. ```void end(WrContext $ctx)``` : Service 종료 시점 ### HttpCall Plugin(httpcall.plug) -1. void call(WrContext $ctx, WrHttpCallRequest $req) : Http Call 요청 시점 +1. ```void call(WrContext $ctx, WrHttpCallRequest $req)``` : Http Call 요청 시점 ### Capture Plugin(capture.plug) - **추가적인 hooking 설정을 통해서만 동작** + **```hook_args_patterns```, ```hook_return_patterns```, ```hook_constructor_patterns``` 에 정의된 method 에서 호출됨** -1. void capArgs(WrContext $ctx, HookArgs $hook) : Method 시작 시점 -2. void capReturn(WrContext $ctx, HookReturn $hook) : Method Return 시점 -3. void capThis(WrContext $ctx, String $class, String $desc, Object $this) : Constructor 생성 시점 +1. ```void capArgs(WrContext $ctx, HookArgs $hook)``` : Method 시작 시점 +2. ```void capReturn(WrContext $ctx, HookReturn $hook)``` : Method Return 시점 +3. ```void capThis(WrContext $ctx, String $class, String $desc, Object $this)``` : Constructor 생성 시점 ### JDBC-Pool Plugin(jdbcpool.plug) -1. String url(WrContext $ctx, String $msg, Object $pool) +1. ```String url(WrContext $ctx, String $msg, Object $pool)``` : DB Connection URL 요청 시점 ## API ### Common API - - void log(Object c) : Logger를 통한 log - - void println(Object c) : System.out를 통한 log - - Object field(Object o, String field) : Object의 filed 값을 가져옴 - - Object method(Object o, String method) : Object의 method를 강제invoke 함 - - Object method1(Object o, String method) : Object의 method를 invoke 함 - - Object method(Object o, String method, String param) : Object의 method를 String 파라미터와 함께 invoke 함 - - String toString(Object o) : Object 를 toString 하여 반환 - - String toString(Object o, String def) : Object 를 toString 하여 반환, null 이면 default string 반환 - - void alert(char level, String title, String message) : Alert 을 보냄 - - int syshash(Object o) : Object 의 identityHash 값 반환 - - int syshash(HookArgs hook, int x) : Arguments의 i 인덱스의 identyHash 값 반환 - - int syshash(HookArgs hook) : This 의 identyHash 값 반환 - - void forward(WrContext wctx, int uuid) : Async Thread 를 App service로 연결 - - void forwardThread(WrContext wctx, int uuid) : Async Thread 를 Background service로 연결 - - void receive(WrContext ctx, int uuid) : 앞서 등록된 Service가 있으면 연결 - + - ```void log(Object c)``` : Logger를 통한 log + - ```void println(Object c)``` : System.out를 통한 log + - ```Object getFieldValue(Object o, String fieldName)``` : get field value as object of 'o' + - ```Object invokeMethod(Object o, String methodName)``` : invoke the method + - ```Object invokeMethod(Object o, String methodName, Object[] args)``` : invoke the method with args + - ```Object invokeMethod(Object o, String methodName, Class[] argTypes, Object[] args)``` : invoke the method with args + - ```Object newInstance(String className)``` : new instance of the class + - ```Object newInstance(String className, ClassLoader loader)``` : new instance of the class from the classloader + - ```Object newInstance(String className, Object[] args)``` : new instance of the class with arguments + - ```Object newInstance(String className, ClassLoader loader, Object[] args)``` : new instance of the class with arguments from the classloader + - ```Object newInstance(String className, ClassLoader loader, Class[] argTypes, Object[] args)``` : new instance of the class with arguments from the classloader + - ```String toString(Object o)``` : Object 를 toString 하여 반환 + - ```String toString(Object o, String def)``` : Object 를 toString 하여 반환, null 이면 default string 반환 + - ```void alert(char level, String title, String message)``` : Alert 을 보냄 (level : i\|w\|e\|f as info, warn, error, fatal). + - ```Class[] makeArgTypes(Class class0, Class class1, ..., classN)``` : assemble argument types array to call the reflection method ```invokeMethod()``` + - ```Object[] makeArgs(Object obj0, Object obj1, ..., objN)``` : assemble arguments array to call the reflection method ```invokeMethod()``` + ### WrContext class API - - String service() : Service Name 을 반환 - - void service(String name) : Service Name 을 set - - int serviceHash() : Service Hash 값을 반환 - - void remoteIp(String ip) : Remote IP 을 set - - String remoteIp() : Remote IP를 반환 - - void error(String err) : 임의의 error 를 주입 - - boolean isError() : 에러 체크 - - void group(String group) : 임의의 group을 set - - String group() : Group을 반환 - - void login(String id) : 임의의 사용자 ID 를 set - - String login() : 사용자 ID를 반환 - - void desc(String desc) : 임의의 Desc를 set - - String desc() : Desc를 반환 - - String httpMethod() : Http Method를 반환 - - String httpQuery() : Http Query를 반환 - - String httpContentType() : Http Content-type을 반환 - - String userAgent() : User-Agent를 반환 - - void profile(String msg) : Msg 를 profile에 기록 - - long txid() : txid 를 반환 - - long gxid() : gxid 를 반환 - - TraceContext inner() : context를 반환 + - ```String service()``` : Service Name 을 반환 + - ```void service(String name)``` : Service Name 을 set + - ```int serviceHash()``` : Service Hash 값을 반환 + - ```void remoteIp(String ip)``` : Remote IP 을 set + - ```String remoteIp()``` : Remote IP를 반환 + - ```void error(String err)``` : 임의의 error 를 주입 + - ```boolean isError()``` : 에러 체크 + - ```void group(String group)``` : 임의의 group을 set + - ```String group()``` : Group을 반환 + - ```void login(String id)``` : 임의의 사용자 ID 를 set + - ```String login()``` : 사용자 ID를 반환 + - ```void desc(String desc)``` : 임의의 Desc를 set + - ```String desc()``` : Desc를 반환 + - ```String httpMethod()``` : Http Method를 반환 + - ```String httpQuery()``` : Http Query를 반환 + - ```String httpContentType()``` : Http Content-type을 반환 + - ```String userAgent()``` : User-Agent를 반환 + - ```void profile(String msg)``` : Msg 를 profile에 기록 + - ```void hashProfile(String msg, int value, int elapsed)``` : profile a message as hash value to the XLog profile + - ```parameterizedProfile(int level, String msgFormat, int elapsed, String[] params)``` : profile a message format with parameters. + - message example : "Hello, my name is %s and my age is %s" + - level : 0-debug, 1-info, 2-warn, 3-error, 4-fatal + - ```long txid()``` : txid 를 반환 + - ```long gxid()``` : gxid 를 반환 + - ```TraceContext inner()``` : context를 반환 ### WrRequest class API - - String getCookie(String key) : Cookie 값을 반환 - - String getRequestURI() : Request URI를 반환 - - String getRemoteAddr() : Remote Address를 반환 - - String getMethod() : Method 를 반환 - - String getQueryString() : Query String을 반환 - - String getParameter(String key) : Parameter를 반환 - - Object getAttribute(String key) : Attribute를 반환 - - String getHeader(String key) : Header값을 반환 - - Enumeration getParameterNames() : Parameter 값들을 반환 - - Enumeration getHeaderNames() : HeaderName들을 반환 - - WrSession getSession() : WrSession객체를 반환 - - Set getSessionNames() : Session Name들을 반환 - - Object getSessionAttribute(String key) : Session 값을 반환 - - Object inner() : Request Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```String getCookie(String key)``` : Cookie 값을 반환 + - ```String getRequestURI()``` : Request URI를 반환 + - ```String getRemoteAddr()``` : Remote Address를 반환 + - ```String getMethod()``` : Method 를 반환 + - ```String getQueryString()``` : Query String을 반환 + - ```String getParameter(String key)``` : Parameter를 반환 + - ```Object getAttribute(String key)``` : Attribute를 반환 + - ```String getHeader(String key)``` : Header값을 반환 + - ```Enumeration getParameterNames()``` : Parameter 값들을 반환 + - ```Enumeration getHeaderNames()``` : HeaderName들을 반환 + - ```WrSession getSession()``` : WrSession객체를 반환 + - ```Set getSessionNames()``` : Session Name들을 반환 + - ```Object getSessionAttribute(String key)``` : Session 값을 반환 + - ```Object inner()``` : Request Object를 반환 + - ```boolean isOk()``` : Plugin 상태 확인 + - ```Throwable error()``` : Error 확인 ### WrResponse class API - - PrintWriter getWriter() : Writer를 반환 - - String getContentType() : Content-type을 반환 - - String getCharacterEncoding() : Character-encoding을 반환 - - Object inner() : Response Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```PrintWriter getWriter()``` : Writer를 반환 + - ```String getContentType()``` : Content-type을 반환 + - ```String getCharacterEncoding()``` : Character-encoding을 반환 + - ```Object inner()``` : Response Object를 반환 + - ```boolean isOk()``` : Plugin 상태 확인 + - ```Throwable error()``` : Error 확인 ### WrSession class API - - getAttribute(String key) : Attribute를 반환 - - Enumeration getAttributeNames() : Attribute Names를 반환 - - Object inner() : Session Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```getAttribute(String key)``` : Attribute를 반환 + - ```Enumeration getAttributeNames()``` : Attribute Names를 반환 + - ```Object inner()``` : Session Object를 반환 + - ```boolean isOk()``` : Plugin 상태 확인 + - ```Throwable error()``` : Error 확인 ### WrHttpCallRequest class API - - void header(Object key, Object value) : Header값 추가 - - Object inner() : Request Object를 반환 - - boolean isOk() : Plugin 상태 확인 - - Throwable error() : Error 확인 + - ```void header(Object key, Object value)``` : Header값 추가 + - ```Object inner()``` : Request Object를 반환 + - ```boolean isOk()``` : Plugin 상태 확인 + - ```Throwable error()``` : Error 확인 ### HookArgs class API - - String getClassName() : Class 이름 반환 - - String getMethodName() : Method 이름 반환 - - String getMethodDesc() : Method 의 Desc 반환 - - Object getThis() : this object 반환 - - Object[] getArgs() : Arguments 반환 - - int getArgCount() : Argument 갯수 반환 + - ```String getClassName()``` : Class 이름 반환 + - ```String getMethodName()``` : Method 이름 반환 + - ```String getMethodDesc()``` : Method 의 Desc 반환 + - ```Object getThis()``` : this object 반환 + - ```Object[] getArgs()``` : Arguments 반환 + - ```int getArgCount()``` : Argument 갯수 반환 ### HookReturn class API - - String getClassName() : Class 이름 반환 - - String getMethodName() : Method 이름 반환 - - String getMethodDesc() : Method 의 Desc 반환 - - Object getThis() : this object 반환 - - Object getReturn() : Return 값 반환 + - ```String getClassName()``` : Class 이름 반환 + - ```String getMethodName()``` : Method 이름 반환 + - ```String getMethodDesc()``` : Method 의 Desc 반환 + - ```Object getThis()``` : this object 반환 + - ```Object getReturn()``` : Return 값 반환 diff --git a/scouter.document/main/Plugin-Guide.md b/scouter.document/main/Plugin-Guide.md index 393152721..10ea3b2a0 100644 --- a/scouter.document/main/Plugin-Guide.md +++ b/scouter.document/main/Plugin-Guide.md @@ -43,13 +43,13 @@ Scouter distribution has the samples and the file name can not be modified. Currently 6 types of scripting plugins are supported. * **alert.plug** - for pre-handling alert * **counter.plug** - for pre-handling performance metrics(counters) -* **object.plug** - for pre-handling monitoring objects(instnats) +* **object.plug** - for pre-handling monitoring objects(instances) * **summary.plug** - for pre-handling performance summary data * **xlog.plug** - for pre-handling xlog data * **xlogprofile.plug** - for pre-handling xlog profile -refer to the link for details. -**[Scripting plugin Server API](Server-Plugin-Scripting.md)** +refer to the link for details. +refer to **[Scripting plugin Server API](Server-Plugin-Scripting.md)**. ### 2. Built-in (type) Plugin Builing scripting plugin is very simple and can be dynamically loaded on runtime environment. @@ -106,7 +106,7 @@ public class NullPlugin { * **```PLUGIN_SERVER_XLOG```** * **```PLUGIN_SERVER_PROFILE```** -#### 3. Sample plugin +#### 2.3. plugin sample Provided sample plugin that just prints the data collected. * Sample plugin : [https://github.com/scouter-project/scouter-plugin-server-null](https://github.com/scouter-project/scouter-plugin-server-null) * Download : [scouter-plugin-server-null.jar](https://github.com/scouter-project/scouter-plugin-server-null/releases/download/v1.0/scouter-plugin-server-null.jar) @@ -114,6 +114,8 @@ Provided sample plugin that just prints the data collected. ### 3. Alert scripting (type) plugin We can build our own alarm rules by handling alert scripting plugins which are able to compose various performance metrics. * [Alert Plugin Guide](./Alert-Plugin-Guide.md) +
+ ## Agent Plugin - Scripting Plugin diff --git a/scouter.document/main/Plugin-Guide_kr.md b/scouter.document/main/Plugin-Guide_kr.md index e881fae1b..bc1f1fa7c 100644 --- a/scouter.document/main/Plugin-Guide_kr.md +++ b/scouter.document/main/Plugin-Guide_kr.md @@ -89,7 +89,7 @@ Plugin 개발시 아래 두가지 사항을 준수하여야 한다. * **```PLUGIN_SERVER_XLOG```** * **```PLUGIN_SERVER_PROFILE```** -#### 3. Sample plugin +#### 2.3. plugin sample 단순히 수집된 데이터를 출력하는 간단한 plugin 샘플을 제공한다. * Sample plugin : [https://github.com/scouter-project/scouter-plugin-server-null](https://github.com/scouter-project/scouter-plugin-server-null) * Download : [scouter-plugin-server-null.jar](https://github.com/scouter-project/scouter-plugin-server-null/releases/download/v1.0/scouter-plugin-server-null.jar) diff --git a/scouter.document/main/PluginHelper-API.md b/scouter.document/main/PluginHelper-API.md new file mode 100644 index 000000000..0b770bc89 --- /dev/null +++ b/scouter.document/main/PluginHelper-API.md @@ -0,0 +1,48 @@ +# PluginHelper Class +![English](https://img.shields.io/badge/language-English-orange.svg) [![Korean](https://img.shields.io/badge/language-Korean-blue.svg)](PluginHelper-API_kr.md) + +### PluginHelper APIs (since v1.7.3) + +| method | desc | +| ------------ | ---------- | +| ```void log(Object)``` | logging | +| ```void println(Object)``` | System.out.println | +| ```NumberFormat getNumberFormatter()``` | get NumberFormat with fraction digit 1 | +| ```NumberFormat getNumberFormatter(int fractionDigits)``` | get NumberFormat | +| ```formatNumber(float\|double\|int\|long)``` | format number with fraction digit 1 | +| ```formatNumber(float\|double\|int\|long val, int fractionDigits)``` | format number | +| ```alertInfo(int objHash, String objType, String title, String message)``` | | +| ```alertWarn(int objHash, String objType, String title, String message)``` | | +| ```alertError(int objHash, String objType, String title, String message)``` | | +| ```alertFatal(int objHash, String objType, String title, String message)``` | | +| ```alert(byte level, int objHash, String objType, String title, String message)``` | | +| ```String getErrorString(String yyyymmdd, int hash)``` | | +| ```String getApicallString(int hash)``` | | +| ```String getApicallString(String yyyymmdd, int hash)``` | if the option ```mgr_text_db_daily_api_enabled``` is true | +| ```String getMethodString(int hash)``` | | +| ```String getServiceString(int hash)``` | | +| ```String getServiceString(String yyyymmdd, int hash)``` | if the option ```mgr_text_db_daily_service_enabled``` is true | +| ```String getSqlString(int hash)``` | | +| ```String getSqlString(String yyyymmdd, int hash)``` | | +| ```String getObjectString(int hash)``` | | +| ```String getRefererString(int hash)``` | | +| ```String getUserAgentString(int hash)``` | | +| ```String getUserGroupString(int hash)``` | | +| ```String getCityString(int hash)``` | | +| ```String getLoginString(int hash)``` | | +| ```String getDescString(int hash)``` | | +| ```String getHashMsgString(int hash)``` | | +| ```Object getFieldValue(Object o, String fieldName)``` | get field value as object of 'o' | +| ```Object invokeMethod(Object o, String methodName)``` | invoke the method | +| ```Object invokeMethod(Object o, String methodName, Object[] args)``` | invoke the method with args | +| ```Object invokeMethod(Object o, String methodName, Class[] argTypes, Object[] args)``` | invoke the method with args | +| ```Object newInstance(String className)``` | new instance of the class | +| ```Object newInstance(String className, ClassLoader loader)``` | new instance of the class from the classloader | +| ```Object newInstance(String className, Object[] args)``` | new instance of the class with arguments | +| ```Object newInstance(String className, ClassLoader loader, Object[] args)``` | new instance of the class with arguments from the classloader | +| ```Object newInstance(String className, ClassLoader loader, Class[] argTypes, Object[] args)``` | new instance of the class with arguments from the classloader | +| ```String toString(Object o)``` | invoke toString() of the object | +| ```String toString(Object o, String def)``` | invoke toString() of the object, if null, return def. | +| ```void alert(char level, String title, String message)``` | invoke alert (level : i\|w\|e\|f as info, warn, error, fatal). | +| ```Class[] makeArgTypes(Class class0, Class class1, ..., classN)``` | assemble argument types array to call the reflection method ```invokeMethod()``` | +| ```Object[] makeArgs(Object obj0, Object obj1, ..., objN)``` | assemble arguments array to call the reflection method ```invokeMethod()``` | \ No newline at end of file diff --git a/scouter.document/main/PluginHelper-API_kr.md b/scouter.document/main/PluginHelper-API_kr.md new file mode 100644 index 000000000..e41a7ee49 --- /dev/null +++ b/scouter.document/main/PluginHelper-API_kr.md @@ -0,0 +1,48 @@ +# PluginHelper Class +![English](https://img.shields.io/badge/language-English-orange.svg) [![Korean](https://img.shields.io/badge/language-Korean-blue.svg)](PluginHelper-API.md) + +### PluginHelper APIs (since v1.7.3) + +| method | desc | +| ------------ | ---------- | +| ```void log(Object)``` | logging | +| ```void println(Object)``` | System.out.println | +| ```NumberFormat getNumberFormatter()``` | get NumberFormat with fraction digit 1 | +| ```NumberFormat getNumberFormatter(int fractionDigits)``` | get NumberFormat | +| ```formatNumber(float\|double\|int\|long)``` | format number with fraction digit 1 | +| ```formatNumber(float\|double\|int\|long val, int fractionDigits)``` | format number | +| ```alertInfo(int objHash, String objType, String title, String message)``` | | +| ```alertWarn(int objHash, String objType, String title, String message)``` | | +| ```alertError(int objHash, String objType, String title, String message)``` | | +| ```alertFatal(int objHash, String objType, String title, String message)``` | | +| ```alert(byte level, int objHash, String objType, String title, String message)``` | | +| ```String getErrorString(String yyyymmdd, int hash)``` | | +| ```String getApicallString(int hash)``` | | +| ```String getApicallString(String yyyymmdd, int hash)``` | if the option ```mgr_text_db_daily_api_enabled``` is true | +| ```String getMethodString(int hash)``` | | +| ```String getServiceString(int hash)``` | | +| ```String getServiceString(String yyyymmdd, int hash)``` | if the option ```mgr_text_db_daily_service_enabled``` is true | +| ```String getSqlString(int hash)``` | | +| ```String getSqlString(String yyyymmdd, int hash)``` | | +| ```String getObjectString(int hash)``` | | +| ```String getRefererString(int hash)``` | | +| ```String getUserAgentString(int hash)``` | | +| ```String getUserGroupString(int hash)``` | | +| ```String getCityString(int hash)``` | | +| ```String getLoginString(int hash)``` | | +| ```String getDescString(int hash)``` | | +| ```String getHashMsgString(int hash)``` | | +| ```Object getFieldValue(Object o, String fieldName)``` | get field value as object of 'o' | +| ```Object invokeMethod(Object o, String methodName)``` | invoke the method | +| ```Object invokeMethod(Object o, String methodName, Object[] args)``` | invoke the method with args | +| ```Object invokeMethod(Object o, String methodName, Class[] argTypes, Object[] args)``` | invoke the method with args | +| ```Object newInstance(String className)``` | new instance of the class | +| ```Object newInstance(String className, ClassLoader loader)``` | new instance of the class from the classloader | +| ```Object newInstance(String className, Object[] args)``` | new instance of the class with arguments | +| ```Object newInstance(String className, ClassLoader loader, Object[] args)``` | new instance of the class with arguments from the classloader | +| ```Object newInstance(String className, ClassLoader loader, Class[] argTypes, Object[] args)``` | new instance of the class with arguments from the classloader | +| ```String toString(Object o)``` | invoke toString() of the object | +| ```String toString(Object o, String def)``` | invoke toString() of the object, if null, return def. | +| ```void alert(char level, String title, String message)``` | invoke alert (level : i\|w\|e\|f as info, warn, error, fatal). | +| ```Class[] makeArgTypes(Class class0, Class class1, ..., classN)``` | assemble argument types array to call the reflection method ```invokeMethod()``` | +| ```Object[] makeArgs(Object obj0, Object obj1, ..., objN)``` | assemble arguments array to call the reflection method ```invokeMethod()``` | \ No newline at end of file diff --git a/scouter.document/main/Server-Plugin-Scripting.md b/scouter.document/main/Server-Plugin-Scripting.md index 38617ff3b..ed7c04d98 100644 --- a/scouter.document/main/Server-Plugin-Scripting.md +++ b/scouter.document/main/Server-Plugin-Scripting.md @@ -3,12 +3,11 @@ ## Collector Plugin - Default File Location : ${COLLECTOR_DIR}/plugin - - Dynamic application - - By java code + - Dynamic application By java code - Plugin Type - Pack Plugin - AlertRule Plugin - + ### Pack Plugin - Adding layer before store incoming data - Type @@ -18,86 +17,92 @@ - SummaryPack Plugin - XLogPack Plugin - ProfilePack Plugin - + #### AlertPack Plugin(alert.plug) -> public void process(AlertPack $pack) +> public void process(AlertPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.AlertPack -> +> > } #### CounterPack Plugin(counter.plug) -> public void process(PerfCounterPack $pack) +> public void process(PerfCounterPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.PerfCounterPack -> +> > } #### ObjectPack Plugin(object.plug) -> public void process(ObjectPack $pack) +> public void process(ObjectPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.ObjectPack -> -> } - +> +> } + #### SummaryPack Plugin(summary.plug) -> public void process(SummaryPack $pack) +> public void process(SummaryPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.SummaryPack -> -> } - +> +> } + #### XLogPack Plugin(xlog.plug or xlogdb.plug) -> public void process(XLogPack $pack) +> public void process(XLogPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.XLogPack -> +> > } - + #### ProfilePack Plugin(xlogprofile.plug) -> public void process(XLogProfilePack $pack) +> public void process(XLogProfilePack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.XLogProfilePack -> +> > } - - + + ### API #### Common API - - void log(Object c) : Logger를 통한 log - - void println(Object c) : System.out를 통한 log - - void logTo(String file, String msg) : 특정 file에 msg를 logging - + - void log(Object c) : logging + - void println(Object c) : standard out + - void logTo(String file, String msg) : logging to a specific file + #### XLog or XLogDB Plugin API - - String objName(XLogPack p) : XLog의 Object Name을 반환 - - String objType(XLogPack p) : XLog의 Object Type을 반환 - - String service(XLogPack p) : XLog의 service를 반환 - - String error(XLogPack p) : XLog의 error를 반환 - - String userAgent(XLogPack p) : XLog의 user-agent를 반환 - - String referer(XLogPack p) : XLog의 referer를 반환 - - String login(XLogPack p) : XLog의 login 값을 반환 - - String desc(XLogPack p) : XLog의 desc 값을 반환 - - String group(XLogPack p) : XLog의 group 값을 반환 - + - String objName(XLogPack p) : get object name + - String objType(XLogPack p) : get object type + - String service(XLogPack p) : get service name + - String error(XLogPack p) : get error name + - String userAgent(XLogPack p) : get user agent + - String referer(XLogPack p) : get referrer + - String login(XLogPack p) : get login value + - String desc(XLogPack p) : get desc value + - String group(XLogPack p) : get group value + +#### $$ (PluginHelper) API (Since v1.7.3) + - Refer to **[PluginHelper API](./PluginHelper-API.md)** + + ### AlertRule Plugin - **TBD** + - Refer to **[Alert Plugin Guide](./Alert-Plugin-Guide.md)** + + diff --git a/scouter.document/main/Server-Plugin-Scripting_kr.md b/scouter.document/main/Server-Plugin-Scripting_kr.md index 121df54f7..012bf747a 100644 --- a/scouter.document/main/Server-Plugin-Scripting_kr.md +++ b/scouter.document/main/Server-Plugin-Scripting_kr.md @@ -3,12 +3,11 @@ ## Collector Plugin - Default File Location : ${COLLECTOR_DIR}/plugin - - Dynamic application - - By java code + - Dynamic application By java code - Plugin Type - Pack Plugin - AlertRule Plugin - + ### Pack Plugin - Adding layer before store incoming data - Type @@ -18,86 +17,90 @@ - SummaryPack Plugin - XLogPack Plugin - ProfilePack Plugin - + #### AlertPack Plugin(alert.plug) -> public void process(AlertPack $pack) +> public void process(AlertPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.AlertPack -> +> > } #### CounterPack Plugin(counter.plug) -> public void process(PerfCounterPack $pack) +> public void process(PerfCounterPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.PerfCounterPack -> +> > } #### ObjectPack Plugin(object.plug) -> public void process(ObjectPack $pack) +> public void process(ObjectPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.ObjectPack -> -> } - +> +> } + #### SummaryPack Plugin(summary.plug) -> public void process(SummaryPack $pack) +> public void process(SummaryPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.SummaryPack -> -> } - +> +> } + #### XLogPack Plugin(xlog.plug or xlogdb.plug) -> public void process(XLogPack $pack) +> public void process(XLogPack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.XLogPack -> +> > } - + #### ProfilePack Plugin(xlogprofile.plug) -> public void process(XLogProfilePack $pack) +> public void process(XLogProfilePack $pack, PluginHelper $$) > { > // your code... > ref.) scouter.lang.pack.XLogProfilePack -> +> > } - - + + ### API #### Common API - - void log(Object c) : Logger를 통한 log - - void println(Object c) : System.out를 통한 log - - void logTo(String file, String msg) : 특정 file에 msg를 logging - + - void log(Object c) : logging + - void println(Object c) : standard out + - void logTo(String file, String msg) : logging to a specific file + #### XLog or XLogDB Plugin API - - String objName(XLogPack p) : XLog의 Object Name을 반환 - - String objType(XLogPack p) : XLog의 Object Type을 반환 - - String service(XLogPack p) : XLog의 service를 반환 - - String error(XLogPack p) : XLog의 error를 반환 - - String userAgent(XLogPack p) : XLog의 user-agent를 반환 - - String referer(XLogPack p) : XLog의 referer를 반환 - - String login(XLogPack p) : XLog의 login 값을 반환 - - String desc(XLogPack p) : XLog의 desc 값을 반환 - - String group(XLogPack p) : XLog의 group 값을 반환 - + - String objName(XLogPack p) : get object name + - String objType(XLogPack p) : get object type + - String service(XLogPack p) : get service name + - String error(XLogPack p) : get error name + - String userAgent(XLogPack p) : get user agent + - String referer(XLogPack p) : get referrer + - String login(XLogPack p) : get login value + - String desc(XLogPack p) : get desc value + - String group(XLogPack p) : get group value + +#### $$ (PluginHelper) API (Since v1.7.3) + - Refer to **[PluginHelper API](./PluginHelper-API_kr.md)** + ### AlertRule Plugin - **TBD** - + - Refer to **[Alert Plugin Guide](./Alert-Plugin-Guide_kr.md)** + + diff --git a/scouter.server.boot/assembly/plugin/ErrorRate.alert b/scouter.server.boot/assembly/plugin/ErrorRate.alert new file mode 100644 index 000000000..46c45bb0e --- /dev/null +++ b/scouter.server.boot/assembly/plugin/ErrorRate.alert @@ -0,0 +1,14 @@ +// void process(RealCounter $counter, PluginHelper $$) {} +// ################################ example below ############################################################ +// $$.println("This is alert plugin for the metric 'Error Rate'); +// float errorRateCurrent = $counter.floatValue(); +// float errorRateLatestAvg = $counter.floatValue(30); //average in latest 30 sec +// int tpsCurrent = $counter.intValue("TPS"); // current TPS (get another counter value by name) +// float errorRate180secBefore = $counter.getAvg(180, 30); // avg of before 180s ~ 150s (duration 30s) +// String alertMessage = $counter.objName() + " : errorRate is " + errorRateCurrent + " in TPS " + tpsCurrent; + +// //fire alert message +// if(errorRateCurrent > errorRate120secBefore * 1.3f) $counter.fatal("Error rate fatal!", alertMessage); +// ########################################################################################################### +// TODO your java code here.. + diff --git a/scouter.server.boot/assembly/plugin/ErrorRate.conf b/scouter.server.boot/assembly/plugin/ErrorRate.conf new file mode 100644 index 000000000..2f2a1eefc --- /dev/null +++ b/scouter.server.boot/assembly/plugin/ErrorRate.conf @@ -0,0 +1,3 @@ +history_size=300 +silent_time=300 +check_term=60 \ No newline at end of file diff --git a/scouter.server.boot/assembly/plugin/alert.plug b/scouter.server.boot/assembly/plugin/alert.plug index 58871ab64..b1eab3d2d 100644 --- a/scouter.server.boot/assembly/plugin/alert.plug +++ b/scouter.server.boot/assembly/plugin/alert.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(AlertPack $pack) +// public void process(AlertPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/counter.plug b/scouter.server.boot/assembly/plugin/counter.plug index d7a2b650a..6a5aacf0f 100644 --- a/scouter.server.boot/assembly/plugin/counter.plug +++ b/scouter.server.boot/assembly/plugin/counter.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(PerfCounterPack $pack) +// public void process(PerfCounterPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/object.plug b/scouter.server.boot/assembly/plugin/object.plug index 62f632f40..c66b5231a 100644 --- a/scouter.server.boot/assembly/plugin/object.plug +++ b/scouter.server.boot/assembly/plugin/object.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(ObjectPack $pack) +// public void process(ObjectPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/readme.md b/scouter.server.boot/assembly/plugin/readme.md index 962bc37d8..f928465bd 100644 --- a/scouter.server.boot/assembly/plugin/readme.md +++ b/scouter.server.boot/assembly/plugin/readme.md @@ -1,7 +1,9 @@ +# This document is deprecated. +Refer to [the document of scouter](https://github.com/scouter-project/scouter/blob/master/scouter.document/main/Plugin-Guide.md) + ## Collector Plugin - Default File Location : ${COLLECTOR_DIR}/plugin - - Dynamic application - - By java code + - Dynamic application By java code - Plugin Type - Pack Plugin - AlertRule Plugin @@ -18,7 +20,7 @@ #### AlertPack Plugin(alert.plug) -> public void process(AlertPack $pack) +> public void process(AlertPack $pack, PluginHelper $$) > { > // your code... @@ -28,7 +30,7 @@ #### CounterPack Plugin(counter.plug) -> public void process(PerfCounterPack $pack) +> public void process(PerfCounterPack $pack, PluginHelper $$) > { > // your code... @@ -38,7 +40,7 @@ #### ObjectPack Plugin(object.plug) -> public void process(ObjectPack $pack) +> public void process(ObjectPack $pack, PluginHelper $$) > { > // your code... @@ -48,7 +50,7 @@ #### SummaryPack Plugin(summary.plug) -> public void process(SummaryPack $pack) +> public void process(SummaryPack $pack, PluginHelper $$) > { > // your code... @@ -56,7 +58,7 @@ > > } -#### XLogPack Plugin(xlog.plug or xlogdb.plug) +#### XLogPack Plugin(xlog.plug or xlogdb.plug, PluginHelper $$) > public void process(XLogPack $pack) > { @@ -66,7 +68,7 @@ > > } -#### ProfilePack Plugin(xlogprofile.plug) +#### ProfilePack Plugin(xlogprofile.plug, PluginHelper $$) > public void process(XLogProfilePack $pack) > { @@ -80,21 +82,18 @@ ### API #### Common API - - void log(Object c) : Logger를 통한 log - - void println(Object c) : System.out를 통한 log - - void logTo(String file, String msg) : 특정 file에 msg를 logging + - void log(Object c) : logging + - void println(Object c) : standard out + - void logTo(String file, String msg) : logging to a specific file #### XLog or XLogDB Plugin API - - String objName(XLogPack p) : XLog의 Object Name을 반환 - - String objType(XLogPack p) : XLog의 Object Type을 반환 - - String service(XLogPack p) : XLog의 service를 반환 - - String error(XLogPack p) : XLog의 error를 반환 - - String userAgent(XLogPack p) : XLog의 user-agent를 반환 - - String referer(XLogPack p) : XLog의 referer를 반환 - - String login(XLogPack p) : XLog의 login 값을 반환 - - String desc(XLogPack p) : XLog의 desc 값을 반환 - - String group(XLogPack p) : XLog의 group 값을 반환 - -### AlertRule Plugin - **TBD** - + - String objName(XLogPack p) : get object name + - String objType(XLogPack p) : get object type + - String service(XLogPack p) : get service name + - String error(XLogPack p) : get error name + - String userAgent(XLogPack p) : get user agent + - String referer(XLogPack p) : get referrer + - String login(XLogPack p) : get login value + - String desc(XLogPack p) : get desc value + - String group(XLogPack p) : get group value + diff --git a/scouter.server.boot/assembly/plugin/summary.plug b/scouter.server.boot/assembly/plugin/summary.plug index 16e547874..f16a56e02 100644 --- a/scouter.server.boot/assembly/plugin/summary.plug +++ b/scouter.server.boot/assembly/plugin/summary.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(SummaryPack $pack) +// public void process(SummaryPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/xlog.plug b/scouter.server.boot/assembly/plugin/xlog.plug index b846dc137..07086a617 100644 --- a/scouter.server.boot/assembly/plugin/xlog.plug +++ b/scouter.server.boot/assembly/plugin/xlog.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(XLogPack $pack) +// public void process(XLogPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/xlogdb.plug b/scouter.server.boot/assembly/plugin/xlogdb.plug index b846dc137..07086a617 100644 --- a/scouter.server.boot/assembly/plugin/xlogdb.plug +++ b/scouter.server.boot/assembly/plugin/xlogdb.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(XLogPack $pack) +// public void process(XLogPack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server.boot/assembly/plugin/xlogprofile.plug b/scouter.server.boot/assembly/plugin/xlogprofile.plug index f5a95d979..a26e06b94 100644 --- a/scouter.server.boot/assembly/plugin/xlogprofile.plug +++ b/scouter.server.boot/assembly/plugin/xlogprofile.plug @@ -1,5 +1,5 @@ // Do not release comments. -// public void process(XLogProfilePack $pack) +// public void process(XLogProfilePack $pack, PluginHelper $$) // { // TODO your java code here.. diff --git a/scouter.server/src/main/java/scouter/server/Configure.java b/scouter.server/src/main/java/scouter/server/Configure.java index 8b4d41c12..444d30065 100644 --- a/scouter.server/src/main/java/scouter/server/Configure.java +++ b/scouter.server/src/main/java/scouter/server/Configure.java @@ -18,7 +18,9 @@ package scouter.server; import scouter.lang.conf.ConfigDesc; +import scouter.lang.conf.ConfigValueType; import scouter.lang.conf.ConfigValueUtil; +import scouter.lang.conf.ValueType; import scouter.lang.value.ListValue; import scouter.lang.value.MapValue; import scouter.net.NetConstants; @@ -188,6 +190,7 @@ public final static synchronized Configure getInstance() { public int mgr_purge_counter_keep_days = 70; @ConfigDesc("Ignored log ID set") + @ConfigValueType(ValueType.COMMA_SEPARATED_VALUE) public StringSet mgr_log_ignore_ids = new StringSet(); //db @@ -483,19 +486,6 @@ public boolean saveText(String text) { return false; } - public static void main(String[] args) { - Configure o = new Configure(true); - StringKeyLinkedMap defMap = ConfigValueUtil.getConfigDefault(o); - StringKeyLinkedMap descMap = ConfigValueUtil.getConfigDescMap(o); - StringEnumer enu = defMap.keys(); - while (enu.hasMoreElements()) { - String key = enu.nextString(); - if (ignoreSet.contains(key)) - continue; - System.out.println(key + " : " + ConfigValueUtil.toValue(defMap.get(key) + (descMap.containsKey(key) ? " (" + descMap.get(key) + ")" : ""))); - } - } - private static HashSet ignoreSet = new HashSet(); static { @@ -527,6 +517,10 @@ public StringKeyLinkedMap getConfigureDesc() { return ConfigValueUtil.getConfigDescMap(this); } + public StringKeyLinkedMap getConfigureValueType() { + return ConfigValueUtil.getConfigValueTypeMap(this); + } + public static StringLinkedSet toOrderSet(String values, String deli) { StringLinkedSet set = new StringLinkedSet(); StringTokenizer nizer = new StringTokenizer(values, deli); @@ -539,4 +533,21 @@ public static StringLinkedSet toOrderSet(String values, String deli) { return set; } + public static void main(String[] args) { + StringKeyLinkedMap map = new Configure().getConfigureValueType(); + System.out.println(map); + +// Configure o = new Configure(true); +// StringKeyLinkedMap defMap = ConfigValueUtil.getConfigDefault(o); +// StringKeyLinkedMap descMap = ConfigValueUtil.getConfigDescMap(o); +// StringEnumer enu = defMap.keys(); +// while (enu.hasMoreElements()) { +// String key = enu.nextString(); +// if (ignoreSet.contains(key)) +// continue; +// System.out.println(key + " : " + ConfigValueUtil.toValue(defMap.get(key) + (descMap.containsKey(key) ? " (" + descMap.get(key) + ")" : ""))); +// } + } + + } diff --git a/scouter.server/src/main/java/scouter/server/plugin/IPlugIn.java b/scouter.server/src/main/java/scouter/server/plugin/IPlugIn.java index 850cec811..920f5c9ae 100644 --- a/scouter.server/src/main/java/scouter/server/plugin/IPlugIn.java +++ b/scouter.server/src/main/java/scouter/server/plugin/IPlugIn.java @@ -15,13 +15,14 @@ * limitations under the License. */ package scouter.server.plugin; -import java.io.FileWriter; -import java.io.PrintWriter; import scouter.server.Logger; import scouter.util.FileUtil; + +import java.io.FileWriter; +import java.io.PrintWriter; public class IPlugIn { - public long lastModified; - public String pluginName; + public long __lastModified; + public String __pluginName; public void log(Object c) { Logger.println(c); } @@ -39,4 +40,6 @@ public void logTo(String file, String msg) { FileUtil.close(pw); } } + + public PluginHelper $$ = PluginHelper.getInstance(); } diff --git a/scouter.server/src/main/java/scouter/server/plugin/IText.java b/scouter.server/src/main/java/scouter/server/plugin/IText.java new file mode 100644 index 000000000..306541f4d --- /dev/null +++ b/scouter.server/src/main/java/scouter/server/plugin/IText.java @@ -0,0 +1,25 @@ +/* + * 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.server.plugin; + +import scouter.lang.pack.TextPack; + + +public class IText extends IPlugIn{ + public void process(TextPack p){} +} diff --git a/scouter.server/src/main/java/scouter/server/plugin/PlugInLoader.java b/scouter.server/src/main/java/scouter/server/plugin/PlugInLoader.java index f471b56f4..d486cf42f 100644 --- a/scouter.server/src/main/java/scouter/server/plugin/PlugInLoader.java +++ b/scouter.server/src/main/java/scouter/server/plugin/PlugInLoader.java @@ -17,10 +17,7 @@ */ package scouter.server.plugin; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.CtNewMethod; +import javassist.*; import scouter.lang.pack.*; import scouter.server.Configure; import scouter.server.Logger; @@ -58,7 +55,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.alerts = null; } else { - if (PlugInManager.alerts == null || PlugInManager.alerts.lastModified != scriptFile.lastModified()) { + if (PlugInManager.alerts == null || PlugInManager.alerts.__lastModified != scriptFile.lastModified()) { PlugInManager.alerts = (IAlert) create(scriptFile, "AlertImpl", IAlert.class, AlertPack.class); } } @@ -66,7 +63,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.counters = null; } else { - if (PlugInManager.counters == null || PlugInManager.counters.lastModified != scriptFile.lastModified()) { + if (PlugInManager.counters == null || PlugInManager.counters.__lastModified != scriptFile.lastModified()) { PlugInManager.counters = (ICounter) create(scriptFile, "CounterImpl", ICounter.class, PerfCounterPack.class); } } @@ -74,7 +71,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.objects = null; } else { - if (PlugInManager.objects == null || PlugInManager.objects.lastModified != scriptFile.lastModified()) { + if (PlugInManager.objects == null || PlugInManager.objects.__lastModified != scriptFile.lastModified()) { PlugInManager.objects = (IObject) create(scriptFile, "ObjectImpl", IObject.class, ObjectPack.class); } } @@ -82,7 +79,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.xlog = null; } else { - if (PlugInManager.xlog == null || PlugInManager.xlog.lastModified != scriptFile.lastModified()) { + if (PlugInManager.xlog == null || PlugInManager.xlog.__lastModified != scriptFile.lastModified()) { PlugInManager.xlog = (IXLog) create(scriptFile, "XLogImpl", IXLog.class, XLogPack.class); } } @@ -90,7 +87,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.xlogdb = null; } else { - if (PlugInManager.xlogdb == null || PlugInManager.xlogdb.lastModified != scriptFile.lastModified()) { + if (PlugInManager.xlogdb == null || PlugInManager.xlogdb.__lastModified != scriptFile.lastModified()) { PlugInManager.xlogdb = (IXLog) create(scriptFile, "XLogDBImpl", IXLog.class, XLogPack.class); } } @@ -98,7 +95,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.xlogProfiles = null; } else { - if (PlugInManager.xlogProfiles == null || PlugInManager.xlogProfiles.lastModified != scriptFile.lastModified()) { + if (PlugInManager.xlogProfiles == null || PlugInManager.xlogProfiles.__lastModified != scriptFile.lastModified()) { PlugInManager.xlogProfiles = (IXLogProfile) create(scriptFile, "XLogProfileImpl", IXLogProfile.class, XLogProfilePack.class); } @@ -107,7 +104,7 @@ private void reloadIfModified(File root) { if (scriptFile.canRead() == false) { PlugInManager.summary = null; } else { - if (PlugInManager.summary == null || PlugInManager.summary.lastModified != scriptFile.lastModified()) { + if (PlugInManager.summary == null || PlugInManager.summary.__lastModified != scriptFile.lastModified()) { PlugInManager.summary = (ISummary) create(scriptFile, "SummaryImpl", ISummary.class, SummaryPack.class); } @@ -136,7 +133,11 @@ private IPlugIn create(File file, String className, Class superClass, Class para URLClassLoader u = (URLClassLoader)this.getClass().getClassLoader(); URL[] urls = u.getURLs(); for(int i = 0; urls!=null && i reflCache = Collections.synchronizedMap(new LinkedHashMap(100)); + + private static PluginHelper instance =new PluginHelper(); + private PluginHelper() {} + + public static PluginHelper getInstance() { + return instance; + } + + public void log(Object c) { + Logger.println(c); + } + + public void println(Object c) { + System.out.println(c); + } + + public NumberFormat getNumberFormatter() { + return getNumberFormatter(1); + } + + public NumberFormat getNumberFormatter(int fractionDigits) { + NumberFormat f = NumberFormat.getInstance(); + f.setMaximumFractionDigits(fractionDigits); + return f; + } + + public String formatNumber(float f) { + return formatNumber(f, 1); + } + + public String formatNumber(float f, int fractionDigits) { + return getNumberFormatter(fractionDigits).format(f); + } + + public String formatNumber(double v) { + return formatNumber(v, 1); + } + + public String formatNumber(double v, int fractionDigits) { + return getNumberFormatter(fractionDigits).format(v); + } + + public String formatNumber(int v) { + return formatNumber(v, 1); + } + + public String formatNumber(int v, int fractionDigits) { + return getNumberFormatter(fractionDigits).format(v); + } + + public String formatNumber(long v) { + return formatNumber(v, 1); + } + + public String formatNumber(long v, int fractionDigits) { + return getNumberFormatter(fractionDigits).format(v); + } + + public void alertInfo(int objHash, String objType, String title, String message) { + alert(AlertLevel.INFO, objHash, objType, title, message); + } + public void alertWarn(int objHash, String objType, String title, String message) { + alert(AlertLevel.WARN, objHash, objType, title, message); + } + public void alertError(int objHash, String objType, String title, String message) { + alert(AlertLevel.ERROR, objHash, objType, title, message); + } + public void alertFatal(int objHash, String objType, String title, String message) { + alert(AlertLevel.FATAL, objHash, objType, title, message); + } + + public void alert(byte level, int objHash, String objType, String title, String message) { + AlertPack p = new AlertPack(); + p.time = System.currentTimeMillis(); + p.level = level; + p.objHash = objHash; + p.objType = objType; + p.title = title; + p.message = message; + AlertCore.add(p); + } + + public String getErrorString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getErrorString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.ERROR, hash); + } + + public String getApicallString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getApicallString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.APICALL, hash); + } + + public String getMethodString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getMethodString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.METHOD, hash); + } + + public String getServiceString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getServiceString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.SERVICE, hash); + } + + public String getSqlString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getSqlString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.SQL, hash); + } + + public String getObjectString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getObjectString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.OBJECT, hash); + } + + public String getRefererString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getRefererString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.REFERER, hash); + } + + public String getUserAgentString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getUserAgentString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.USER_AGENT, hash); + } + + public String getUserGroupString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getUserGroupString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.GROUP, hash); + } + + public String getCityString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getCityString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.CITY, hash); + } + + public String getLoginString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getLoginString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.LOGIN, hash); + } + + public String getDescString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getDescString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.DESC, hash); + } + + public String getWebString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getWebString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.WEB, hash); + } + + public String getHashMsgString(int hash) { + return getErrorString(NO_DATE, hash); + } + public String getHashMsgString(String yyyymmdd, int hash) { + return TextRD.getString(yyyymmdd, TextTypes.HASH_MSG, hash); + } + + public static Object invokeMethod(Object o, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Object[] objs = {}; + return invokeMethod(o, methodName, objs); + } + + public static Object invokeMethod(Object o, String methodName, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + int argsSize = args.length; + StringBuilder signature = new StringBuilder(o.getClass().getName()).append(":").append(methodName).append("():"); + + Class[] argClazzes = new Class[argsSize]; + + for(int i=0; i:"); + + for(int i=0; i { + p.put(entry.getKey(), entry.getValue().getType()) + }) + dout.writeByte(TcpFlag.HasNEXT); + dout.writePack(p); + } else { + val o = AgentManager.getAgent(objHash); + val p = AgentCall.call(o, RequestCmd.CONFIGURE_VALUE_TYPE, param); + if (p != null) { + dout.writeByte(TcpFlag.HasNEXT); + dout.writePack(p); + } + } + } +}