提交 da31e04f 编写于 作者: U unknown

modify the model

......@@ -34,7 +34,7 @@
<plugin>
<groupId>com.site.maven.plugins</groupId>
<artifactId>maven-codegen-plugin</artifactId>
<version>1.0.3</version>
<version>1.0.6</version>
<executions>
<execution>
<id>generate failure report model</id>
......
package com.dianping.cat.consumer;
import com.dianping.cat.consumer.failure.FailureReportAnalyzer;
import com.dianping.cat.consumer.ip.IpAnalyzer;
import com.dianping.cat.consumer.transaction.TransactionReportAnalyzer;
import com.dianping.cat.message.spi.MessageAnalyzer;
import com.site.lookup.ContainerHolder;
......@@ -20,7 +21,12 @@ public class DefaultAnalyzerFactory extends ContainerHolder implements AnalyzerF
return analyzer;
} else if (name.equals("transaction")) {
TransactionReportAnalyzer analyzer = lookup(TransactionReportAnalyzer.class);
analyzer.setAnalyzerInfo(start, duration, domain, extraTime);
return analyzer;
} else if (name.equals("ip")) {
IpAnalyzer analyzer = lookup(IpAnalyzer.class);
return analyzer;
}
......
......@@ -99,6 +99,9 @@ public class RealtimeConsumer extends ContainerHolder implements MessageConsumer
@Inject
private long m_extraTime = FIVE_MINUTES;
@Inject
private int m_threads = 10;
@Inject
private List<String> m_analyzerNames;
......@@ -106,8 +109,6 @@ public class RealtimeConsumer extends ContainerHolder implements MessageConsumer
@Inject
private AnalyzerFactory m_factory;
private int m_threads = 10;
private ExecutorService m_executor;
private List<Period> m_periods = new ArrayList<Period>(PROCESS_PERIOD);
......
......@@ -11,6 +11,7 @@ import com.dianping.cat.consumer.failure.FailureReportAnalyzer;
import com.dianping.cat.consumer.failure.FailureReportAnalyzer.FailureHandler;
import com.dianping.cat.consumer.failure.FailureReportAnalyzer.Handler;
import com.dianping.cat.consumer.failure.FailureReportAnalyzer.LongUrlHandler;
import com.dianping.cat.consumer.ip.IpAnalyzer;
import com.dianping.cat.consumer.transaction.TransactionReportAnalyzer;
import com.dianping.cat.message.spi.MessageConsumer;
import com.dianping.cat.message.spi.MessageManager;
......@@ -31,7 +32,7 @@ public class ComponentsConfigurator extends AbstractResourceConfigurator {
all.add(C(MessageConsumer.class, "realtime", RealtimeConsumer.class) //
.req(AnalyzerFactory.class).config(E("consumerId").value("realtime") //
, E("extraTime").value("300000")//
, E("analyzerNames").value("failure,transaction")));
, E("analyzerNames").value("failure,transaction,ip")));
String failureTypes = "Error,RuntimeException,Exception";
......@@ -52,6 +53,8 @@ public class ComponentsConfigurator extends AbstractResourceConfigurator {
.req(MessageManager.class) //
.config(E("reportPath").value("target/report/transaction/"))
.req(MessageStorage.class, "html"));
all.add(C(IpAnalyzer.class).is(PER_LOOKUP));
return all;
}
......
......@@ -24,11 +24,7 @@ public class FailureReportStore {
public static String getStoreString(FailureReport report) {
StringBuilder result = new StringBuilder();
DefaultJsonBuilder jsonBuilder = new DefaultJsonBuilder();
jsonBuilder.visitFailureReport(report);
String jsonString = jsonBuilder.getString();
String jsonString = new DefaultJsonBuilder().buildJson(report);
result.append("<html>").append(END).append("<head>").append(END).append("<title>").append(END).append(
"Failure Report ").append("From ").append(SDF.format(report.getStartTime())).append(" To ").append(
......
package com.dianping.cat.consumer.ip;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dianping.cat.consumer.ip.model.entity.Ip;
import com.dianping.cat.consumer.ip.model.entity.IpReport;
import com.dianping.cat.consumer.ip.model.entity.Period;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.spi.AbstractMessageAnalyzer;
import com.dianping.cat.message.spi.MessageTree;
public class IpAnalyzer extends AbstractMessageAnalyzer<IpReport> {
private static final String TOKEN = "RemoteIP=";
@Override
protected void store(List<IpReport> result) {
// TODO Auto-generated method stub
}
private Map<String, IpReport> m_reports = new HashMap<String, IpReport>();
private int m_lastPhase;
private IpReport findOrCreateReport(String domain) {
IpReport report = m_reports.get(domain);
if (report == null) {
synchronized (m_reports) {
report = m_reports.get(domain);
if (report == null) {
report = new IpReport().setDomain(domain);
m_reports.put(domain, report);
}
}
}
return report;
}
@Override
public List<IpReport> generate() {
// TODO Auto-generated method stub
return null;
}
public List<IpReport> generate() {
return null;
}
public List<String> getDomains() {
List<String> domains = new ArrayList<String>(m_reports.keySet());
Collections.sort(domains, new Comparator<String>() {
@Override
public int compare(String d1, String d2) {
if (d1.equals("Cat")) {
return 1;
}
return d1.compareTo(d2);
}
});
return domains;
}
public IpReport generate(String domain) {
if (domain != null) {
IpReport report = m_reports.get(domain);
return report;
} else {
return null;
}
}
private String getIpAddress(Transaction root) {
List<Message> children = ((Transaction) root).getChildren();
for (Message child : children) {
if (child instanceof Event && child.getType().equals("URL") && child.getName().equals("ClientInfo")) {
String data = child.getData().toString();
int off = data.indexOf(TOKEN);
if (off >= 0) {
int pos = data.indexOf('&', off + TOKEN.length());
if (pos > 0) {
return data.substring(off + TOKEN.length(), pos);
}
}
break;
}
}
return null;
}
@Override
protected void process(MessageTree tree) {
// TODO Auto-generated method stub
}
protected boolean isTimeout() {
return false;
}
@Override
protected boolean isTimeout() {
// TODO Auto-generated method stub
return false;
}
protected void process(MessageTree tree) {
Message root = tree.getMessage();
if (root instanceof Transaction) {
String address = getIpAddress((Transaction) root);
if (address == null) {
address = "N/A";
}
String domain = tree.getDomain();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(root.getTimestamp());
int minute = cal.get(Calendar.MINUTE);
IpReport report = findOrCreateReport(domain);
Period period = report.findOrCreatePeriod(minute);
Ip ip = period.findOrCreateIp(address);
ip.incCount();
clearLastPhase();
}
}
private void clearLastPhase() {
Calendar cal = Calendar.getInstance();
int minute = cal.get(Calendar.MINUTE);
int currentPhase = minute / 20; // 0, 1, 2
if (m_lastPhase != currentPhase) {
int baseIndex = m_lastPhase * 20;
List<String> domains = new ArrayList<String>();
for (Map.Entry<String, IpReport> e : m_reports.entrySet()) {
IpReport report = e.getValue();
Map<Integer, Period> periods = report.getPeriods();
for (int i = 0; i < 20; i++) {
periods.remove(baseIndex + i);
}
if (periods.isEmpty()) {
domains.add(e.getKey());
}
}
for (String domain : domains) {
m_reports.remove(domain);
}
m_lastPhase = currentPhase;
}
}
@Override
protected void store(List<IpReport> reports) {
}
}
......@@ -63,49 +63,55 @@ public class TransactionReportAnalyzer extends AbstractMessageAnalyzer<Transacti
if (report == null) {
return report;
}
for (TransactionType type : report.getTypes().values()) {
long typeCount = 0;
long typeFailCount = 0;
double typeSum = 0;
double typeSum2 = 0;
Collection<TransactionName> names = type.getNames().values();
for (TransactionName name : names) {
long count = name.getTotalCount();
double sum = name.getSum();
double ave = sum / count;
double sum2 = name.getSum2();
double std = std(count, ave, sum2);
long failCount = name.getFailCount();
double failPercent = 100.0 * failCount / count;
name.setFailPercent(failPercent);
name.setAvg(ave);
name.setStd(std);
typeCount += count;
typeSum += sum;
typeSum2 += sum2;
typeFailCount += failCount;
if (type.getSuccessMessageUrl() == null && name.getSuccessMessageUrl() != null) {
type.setSuccessMessageUrl(name.getSuccessMessageUrl());
}
if (type.getFailMessageUrl() == null && name.getFailMessageUrl() != null) {
type.setFailMessageUrl(name.getFailMessageUrl());
}
type.setMax(Math.max(name.getMax(), type.getMax()));
type.setMin(Math.min(name.getMin(), type.getMin()));
}
type.setTotalCount(typeCount);
type.setFailCount(typeFailCount);
type.setSum(typeSum);
type.setSum2(typeSum2);
double typeAvg = typeSum / typeCount;
type.setAvg(typeAvg);
type.setFailPercent(100.0 * typeFailCount / typeCount);
type.setStd(std(typeCount, typeAvg, typeSum2));
doOneType(type);
}
return report;
}
/**
* @param type
*/
public void doOneType(TransactionType type) {
long typeCount = 0;
long typeFailCount = 0;
double typeSum = 0;
double typeSum2 = 0;
Collection<TransactionName> names = type.getNames().values();
for (TransactionName name : names) {
long count = name.getTotalCount();
double sum = name.getSum();
double ave = sum / count;
double sum2 = name.getSum2();
double std = std(count, ave, sum2);
long failCount = name.getFailCount();
double failPercent = 100.0 * failCount / count;
name.setFailPercent(failPercent);
name.setAvg(ave);
name.setStd(std);
typeCount += count;
typeSum += sum;
typeSum2 += sum2;
typeFailCount += failCount;
if (type.getSuccessMessageUrl() == null && name.getSuccessMessageUrl() != null) {
type.setSuccessMessageUrl(name.getSuccessMessageUrl());
}
if (type.getFailMessageUrl() == null && name.getFailMessageUrl() != null) {
type.setFailMessageUrl(name.getFailMessageUrl());
}
type.setMax(Math.max(name.getMax(), type.getMax()));
type.setMin(Math.min(name.getMin(), type.getMin()));
}
type.setTotalCount(typeCount);
type.setFailCount(typeFailCount);
type.setSum(typeSum);
type.setSum2(typeSum2);
double typeAvg = typeSum / typeCount;
type.setAvg(typeAvg);
type.setFailPercent(100.0 * typeFailCount / typeCount);
type.setStd(std(typeCount, typeAvg, typeSum2));
}
@Override
public void enableLogging(Logger logger) {
m_logger = logger;
......@@ -187,12 +193,12 @@ public class TransactionReportAnalyzer extends AbstractMessageAnalyzer<Transacti
if (tree != null) {
if (t.isSuccess()) {
if (name.getSuccessMessageUrl() == null) {
String url = this.messageStorage.store(tree);
String url = this.messageStorage.store(tree); // store first success
name.setSuccessMessageUrl(url);
}
} else {
String url = this.messageStorage.store(tree); // store all errors
if (name.getFailMessageUrl() == null) {
String url = this.messageStorage.store(tree);
name.setFailMessageUrl(url);
}
}
......@@ -256,12 +262,8 @@ public class TransactionReportAnalyzer extends AbstractMessageAnalyzer<Transacti
file.getParentFile().mkdirs();
DefaultJsonBuilder builder = new DefaultJsonBuilder();
report.accept(builder);
try {
Files.forIO().writeTo(file, builder.getString());
Files.forIO().writeTo(file, new DefaultJsonBuilder().buildJson(report));
} catch (IOException e) {
m_logger.error(String.format("Error when writing to file(%s)!", file), e);
}
......
......@@ -4,9 +4,9 @@
<attribute name="domain" value-type="String" />
<attribute name="startTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="endTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<entity-ref name="segment" type="list" names="segments" />
<entity-ref name="period" type="list" names="periods" />
</entity>
<entity name="segment">
<entity name="period">
<attribute name="minute" value-type="int" />
<entity-ref name="ip" type="list" names="ips" />
</entity>
......
......@@ -2,15 +2,14 @@
<model model-package="com.dianping.cat.consumer.ip.model" enable-merger="true" enable-json-builder="true"
enable-xml-parser="true" enable-base-visitor="true">
<entity name="ip-report" root="true">
<entity-ref name="segment" type="map" names="segments" />
<entity-ref name="period" type="map" names="periods" method-find-or-create="true" />
</entity>
<entity name="segment">
<entity name="period">
<attribute name="minute" value-type="int" key="true" />
<entity-ref name="ip" type="map" names="ips" />
<entity-ref name="ip" type="map" names="ips" method-find-or-create="true" />
</entity>
<entity name="ip">
<attribute name="address" value-type="String" key="true"/>
<attribute name="count" value-type="int" format="#,###,###"/>
<attribute name="address" value-type="String" key="true" />
<attribute name="count" value-type="int" primitive="true" method-inc="true" />
</entity>
</model>
......@@ -16,7 +16,7 @@
<configuration>
<consumerId>realtime</consumerId>
<extraTime>300000</extraTime>
<analyzerNames>failure,transaction</analyzerNames>
<analyzerNames>failure,transaction,ip</analyzerNames>
</configuration>
<requirements>
<requirement>
......@@ -90,5 +90,10 @@
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.consumer.ip.IpAnalyzer</role>
<implementation>com.dianping.cat.consumer.ip.IpAnalyzer</implementation>
<instantiation-strategy>per-lookup</instantiation-strategy>
</component>
</components>
</plexus>
......@@ -6,19 +6,24 @@ import org.junit.runners.Suite.SuiteClasses;
import com.dianping.cat.consumer.failure.FailureAnalyzerStoreTest;
import com.dianping.cat.consumer.failure.FailureAnalyzerTest;
import com.dianping.cat.consumer.ip.IpAnalyzerTest;
import com.dianping.cat.consumer.transaction.NumberFormatTest;
import com.dianping.cat.consumer.transaction.TransactionReportMessageAnalyzerTest;
@RunWith(Suite.class)
@SuiteClasses({
/* .impl */
ManyAnalyzerTest.class,
OneAnalyzerTwoDurationTest.class,
/* .model.failure */
FailureAnalyzerTest.class, FailureAnalyzerStoreTest.class,
/* .failure */
FailureAnalyzerTest.class,
FailureAnalyzerStoreTest.class,
/* .ip */
IpAnalyzerTest.class,
/* .transaction */
NumberFormatTest.class,
......
......@@ -67,10 +67,7 @@ public class FailureAnalyzerStoreTest extends ComponentTestCase {
analyzer.store(report);
FailureReport targetReport = analyzer.generateByDomainAndIp(m_domain,m_host);
DefaultJsonBuilder builder = new DefaultJsonBuilder();
builder.visitFailureReport(targetReport);
String json = builder.getString();
String json = new DefaultJsonBuilder().buildJson(targetReport);
String expected = Files.forIO().readFrom(getResourceFile("failure.json"), "utf-8");
Assert.assertEquals("Check json content!", expected.replace("\r", ""), json.replace("\r", ""));
......
......@@ -11,7 +11,6 @@ import com.dianping.cat.consumer.AnalyzerFactory;
import com.dianping.cat.consumer.transaction.model.entity.TransactionName;
import com.dianping.cat.consumer.transaction.model.entity.TransactionReport;
import com.dianping.cat.consumer.transaction.model.entity.TransactionType;
import com.dianping.cat.consumer.transaction.model.transform.DefaultJsonBuilder;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.internal.DefaultTransaction;
import com.dianping.cat.message.spi.MessageTree;
......@@ -92,10 +91,9 @@ public class TransactionReportMessageAnalyzerTest extends ComponentTestCase{
assertEquals(1000.0, n2.getMax());
assertEquals(500.5, n2.getAvg());
assertEquals(500500.0, n2.getSum());
DefaultJsonBuilder builder = new DefaultJsonBuilder();
report.accept( builder);
System.out.println(builder.getString());
System.out.println(report.toString());
// System.out.println(new DefaultJsonBuilder().buildJson(report));
// System.out.println(report.toString());
}
}
<ip-report domain="Review" startTime="2012-01-25 13:00:00" endTime="2012-01-25 13:59:00">
<segment minute="24">
<ip address="127.0.0.1" count="123"/>
<ip address="192.168.63.30" count="3"/>
</segment>
<segment>
</segment>
<period minute="0">
<ip address="127.0.0.1" count="19"/>
<ip address="192.168.63.30" count="11"/>
</period>
<period minute="1">
</period>
</ip-report>
;(function($){
/**
* jqGrid English Translation
* Tony Tomov tony@trirand.com
* http://trirand.com/blog/
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
**/
$.jgrid = {
defaults : {
recordtext: "View {0} - {1} of {2}",
emptyrecords: "No records to view",
loadtext: "Loading...",
pgtext : "Page {0} of {1}"
},
search : {
caption: "Search...",
Find: "Find",
Reset: "Reset",
odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
matchText: " match",
rulesText: " rules"
},
edit : {
addCaption: "Add Record",
editCaption: "Edit Record",
bSubmit: "Submit",
bCancel: "Cancel",
bClose: "Close",
saveData: "Data has been changed! Save changes?",
bYes : "Yes",
bNo : "No",
bExit : "Cancel",
msg: {
required:"Field is required",
number:"Please, enter valid number",
minValue:"value must be greater than or equal to ",
maxValue:"value must be less than or equal to",
email: "is not a valid e-mail",
integer: "Please, enter valid integer value",
date: "Please, enter valid date value",
url: "is not a valid URL. Prefix required ('http://' or 'https://')",
nodefined : " is not defined!",
novalue : " return value is required!",
customarray : "Custom function should return array!",
customfcheck : "Custom function should be present in case of custom checking!"
}
},
view : {
caption: "View Record",
bClose: "Close"
},
del : {
caption: "Delete",
msg: "Delete selected record(s)?",
bSubmit: "Delete",
bCancel: "Cancel"
},
nav : {
edittext: "",
edittitle: "Edit selected row",
addtext:"",
addtitle: "Add new row",
deltext: "",
deltitle: "Delete selected row",
searchtext: "",
searchtitle: "Find records",
refreshtext: "",
refreshtitle: "Reload Grid",
alertcap: "Warning",
alerttext: "Please, select row",
viewtext: "",
viewtitle: "View selected row"
},
col : {
caption: "Select columns",
bSubmit: "Ok",
bCancel: "Cancel"
},
errors : {
errcap : "Error",
nourl : "No url is set",
norecords: "No records to process",
model : "Length of colNames <> colModel!"
},
formatter : {
integer : {thousandsSeparator: " ", defaultValue: '0'},
number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
date : {
dayNames: [
"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
],
AmPm : ["am","pm","AM","PM"],
S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
srcformat: 'Y-m-d',
newformat: 'd/m/Y',
masks : {
ISO8601Long:"Y-m-d H:i:s",
ISO8601Short:"Y-m-d",
ShortDate: "n/j/Y",
LongDate: "l, F d, Y",
FullDateTime: "l, F d, Y g:i:s A",
MonthDay: "F d",
ShortTime: "g:i A",
LongTime: "g:i:s A",
SortableDateTime: "Y-m-d\\TH:i:s",
UniversalSortableDateTime: "Y-m-d H:i:sO",
YearMonth: "F, Y"
},
reformatAfterEdit : false
},
baseLinkUrl: '',
showAction: '',
target: '',
checkbox : {disabled:true},
idName : 'id'
}
};
})(jQuery);
/*Grid*/
.ui-jqgrid {position: relative; font-size:11px;}
.ui-jqgrid .ui-jqgrid-view {position: relative;left:0px; top: 0px; padding: .0em;}
/* caption*/
.ui-jqgrid .ui-jqgrid-titlebar {padding: .3em .2em .2em .3em; position: relative; border-left: 0px none;border-right: 0px none; border-top: 0px none;}
.ui-jqgrid .ui-jqgrid-title { float: left; margin: .1em 0 .2em; }
.ui-jqgrid .ui-jqgrid-titlebar-close { position: absolute;top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height:18px;}.ui-jqgrid .ui-jqgrid-titlebar-close span { display: block; margin: 1px; }
.ui-jqgrid .ui-jqgrid-titlebar-close:hover { padding: 0; }
/* header*/
.ui-jqgrid .ui-jqgrid-hdiv {position: relative; margin: 0em;padding: 0em; overflow-x: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
.ui-jqgrid .ui-jqgrid-hbox {float: left; padding-right: 20px;}
.ui-jqgrid .ui-jqgrid-htable {table-layout:fixed;margin:0em;}
.ui-jqgrid .ui-jqgrid-htable th {height:22px;padding: 0 2px 0 2px;}
.ui-jqgrid .ui-jqgrid-htable th div {overflow: hidden; position:relative; height:17px;}
.ui-th-column, .ui-jqgrid .ui-jqgrid-htable th.ui-th-column {overflow: hidden;white-space: nowrap;text-align:center;border-top : 0px none;border-bottom : 0px none;}
.ui-th-ltr, .ui-jqgrid .ui-jqgrid-htable th.ui-th-ltr {border-left : 0px none;}
.ui-th-rtl, .ui-jqgrid .ui-jqgrid-htable th.ui-th-rtl {border-right : 0px none;}
.ui-first-th-ltr {border-right: 1px solid; }
.ui-first-th-rtl {border-left: 1px solid; }
.ui-jqgrid .ui-th-div-ie {white-space: nowrap; zoom :1; height:17px;}
.ui-jqgrid .ui-jqgrid-resize {height:20px !important;position: relative; cursor :e-resize;display: inline;overflow: hidden;}
.ui-jqgrid .ui-grid-ico-sort {overflow:hidden;position:absolute;display:inline; cursor: pointer !important;}
.ui-jqgrid .ui-icon-asc {margin-top:-3px; height:12px;}
.ui-jqgrid .ui-icon-desc {margin-top:3px;height:12px;}
.ui-jqgrid .ui-i-asc {margin-top:0px;height:16px;}
.ui-jqgrid .ui-i-desc {margin-top:0px;margin-left:13px;height:16px;}
.ui-jqgrid .ui-jqgrid-sortable {cursor:pointer;}
.ui-jqgrid tr.ui-search-toolbar th { border-top-width: 1px !important; border-top-color: inherit !important; border-top-style: ridge !important }
tr.ui-search-toolbar input {margin: 1px 0px 0px 0px}
tr.ui-search-toolbar select {margin: 1px 0px 0px 0px}
/* body */
.ui-jqgrid .ui-jqgrid-bdiv {position: relative; margin: 0em; padding:0; overflow: auto; text-align:left;}
.ui-jqgrid .ui-jqgrid-btable {table-layout:fixed; margin:0em; outline-style: none; }
.ui-jqgrid tr.jqgrow { outline-style: none; }
.ui-jqgrid tr.jqgroup { outline-style: none; }
.ui-jqgrid tr.jqgrow td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
.ui-jqgrid tr.jqgfirstrow td {padding: 0 2px 0 2px;border-right-width: 1px; border-right-style: solid;}
.ui-jqgrid tr.jqgroup td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
.ui-jqgrid tr.jqfoot td {font-weight: bold; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
.ui-jqgrid tr.ui-row-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
.ui-jqgrid tr.ui-row-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
.ui-jqgrid td.jqgrid-rownum { padding: 0 2px 0 2px; margin: 0px; border: 0px none;}
.ui-jqgrid .ui-jqgrid-resize-mark { width:2px; left:0; background-color:#777; cursor: e-resize; cursor: col-resize; position:absolute; top:0; height:100px; overflow:hidden; display:none; border:0 none;}
/* footer */
.ui-jqgrid .ui-jqgrid-sdiv {position: relative; margin: 0em;padding: 0em; overflow: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
.ui-jqgrid .ui-jqgrid-ftable {table-layout:fixed; margin-bottom:0em;}
.ui-jqgrid tr.footrow td {font-weight: bold; overflow: hidden; white-space:nowrap; height: 21px;padding: 0 2px 0 2px;border-top-width: 1px; border-top-color: inherit; border-top-style: solid;}
.ui-jqgrid tr.footrow-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
.ui-jqgrid tr.footrow-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
/* Pager*/
.ui-jqgrid .ui-jqgrid-pager { border-left: 0px none !important;border-right: 0px none !important; border-bottom: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px;white-space: nowrap;overflow: hidden;}
.ui-jqgrid .ui-pager-control {position: relative;}
.ui-jqgrid .ui-pg-table {position: relative; padding-bottom:2px; width:auto; margin: 0em;}
.ui-jqgrid .ui-pg-table td {font-weight:normal; vertical-align:middle; padding:1px;}
.ui-jqgrid .ui-pg-button { height:19px !important;}
.ui-jqgrid .ui-pg-button span { display: block; margin: 1px; float:left;}
.ui-jqgrid .ui-pg-button:hover { padding: 0px; }
.ui-jqgrid .ui-state-disabled:hover {padding:1px;}
.ui-jqgrid .ui-pg-input { height:13px;font-size:.8em; margin: 0em;}
.ui-jqgrid .ui-pg-selbox {font-size:.8em; line-height:18px; display:block; height:18px; margin: 0em;}
.ui-jqgrid .ui-separator {height: 18px; border-left: 1px solid #ccc ; border-right: 1px solid #ccc ; margin: 1px; float: right;}
.ui-jqgrid .ui-paging-info {font-weight: normal;height:19px; margin-top:3px;margin-right:4px;}
.ui-jqgrid .ui-jqgrid-pager .ui-pg-div {padding:1px 0;float:left;list-style-image:none;list-style-position:outside;list-style-type:none;position:relative;}
.ui-jqgrid .ui-jqgrid-pager .ui-pg-button { cursor:pointer; }
.ui-jqgrid .ui-jqgrid-pager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
.ui-jqgrid td input, .ui-jqgrid td select .ui-jqgrid td textarea { margin: 0em;}
.ui-jqgrid td textarea {width:auto;height:auto;}
.ui-jqgrid .ui-jqgrid-toppager {border-left: 0px none !important;border-right: 0px none !important; border-top: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px !important;white-space: nowrap;overflow: hidden;}
/*subgrid*/
.ui-jqgrid .ui-jqgrid-btable .ui-sgcollapsed span {display: block;}
.ui-jqgrid .ui-subgrid {margin:0em;padding:0em; width:100%;}
.ui-jqgrid .ui-subgrid table {table-layout: fixed;}
.ui-jqgrid .ui-subgrid tr.ui-subtblcell td {height:18px;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
.ui-jqgrid .ui-subgrid td.subgrid-data {border-top: 0px none !important;}
.ui-jqgrid .ui-subgrid td.subgrid-cell {border-width: 0px 0px 1px 0px;}
.ui-jqgrid .ui-th-subgrid {height:20px;}
/* loading */
.ui-jqgrid .loading {position: absolute; top: 45%;left: 45%;width: auto;z-index:101;padding: 6px; margin: 5px;text-align: center;font-weight: bold;display: none;border-width: 2px !important;}
.ui-jqgrid .jqgrid-overlay {display:none;z-index:100;}
* html .jqgrid-overlay {width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
* .jqgrid-overlay iframe {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
/* end loading div */
/* toolbar */
.ui-jqgrid .ui-userdata {border-left: 0px none; border-right: 0px none; height : 21px;overflow: hidden; }
/*Modal Window */
.ui-jqdialog { display: none; width: 300px; position: absolute; padding: .2em; font-size:11px; overflow:visible;}
.ui-jqdialog .ui-jqdialog-titlebar { padding: .3em .2em; position: relative; }
.ui-jqdialog .ui-jqdialog-title { margin: .1em 0 .2em; }
.ui-jqdialog .ui-jqdialog-titlebar-close { position: absolute; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-jqdialog .ui-jqdialog-titlebar-close span { display: block; margin: 1px; }
.ui-jqdialog .ui-jqdialog-titlebar-close:hover, .ui-jqdialog .ui-jqdialog-titlebar-close:focus { padding: 0; }
.ui-jqdialog-content, .ui-jqdialog .ui-jqdialog-content { border: 0; padding: .3em .2em; background: none; height:auto;}
.ui-jqdialog .ui-jqconfirm {padding: .4em 1em; border-width:3px;position:absolute;bottom:10px;right:10px;overflow:visible;display:none;height:80px;width:220px;text-align:center;}
/* end Modal window*/
/* Form edit */
.ui-jqdialog-content .FormGrid {margin: 0px;}
.ui-jqdialog-content .EditTable { width: 100%; margin-bottom:0em;}
.ui-jqdialog-content .DelTable { width: 100%; margin-bottom:0em;}
.EditTable td input, .EditTable td select, .EditTable td textarea {margin: 0em;}
.EditTable td textarea { width:auto; height:auto;}
.ui-jqdialog-content td.EditButton {text-align: right;border-top: 0px none;border-left: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
.ui-jqdialog-content td.navButton {text-align: center; border-left: 0px none;border-top: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
.ui-jqdialog-content input.FormElement {padding:.3em}
.ui-jqdialog-content .data-line {padding-top:.1em;border: 0px none;}
.ui-jqdialog-content .CaptionTD {text-align: left; vertical-align: middle;border: 0px none; padding: 2px;white-space: nowrap;}
.ui-jqdialog-content .DataTD {padding: 2px; border: 0px none; vertical-align: top;}
.ui-jqdialog-content .form-view-data {white-space:pre}
.fm-button { display: inline-block; margin:0 4px 0 0; padding: .4em .5em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
.fm-button-icon-left { padding-left: 1.9em; }
.fm-button-icon-right { padding-right: 1.9em; }
.fm-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px; }
.fm-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px;}
#nData, #pData { float: left; margin:3px;padding: 0; width: 15px; }
/* End Eorm edit */
/*.ui-jqgrid .edit-cell {}*/
.ui-jqgrid .selected-row, div.ui-jqgrid .selected-row td {font-style : normal;border-left: 0px none;}
/* Tree Grid */
.ui-jqgrid .tree-wrap {float: left; position: relative;height: 18px;white-space: nowrap;overflow: hidden;}
.ui-jqgrid .tree-minus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
.ui-jqgrid .tree-plus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
.ui-jqgrid .tree-leaf {position: absolute; height: 18px; width: 18px;overflow: hidden;}
.ui-jqgrid .treeclick {cursor: pointer;}
/* moda dialog */
* iframe.jqm {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
.ui-jqgrid-dnd tr td {border-right-width: 1px; border-right-color: inherit; border-right-style: solid; height:20px}
/* RTL Support */
.ui-jqgrid .ui-jqgrid-title-rtl {float:right;margin: .1em 0 .2em; }
.ui-jqgrid .ui-jqgrid-hbox-rtl {float: right; padding-left: 20px;}
.ui-jqgrid .ui-jqgrid-resize-ltr {float: right;margin: -2px -2px -2px 0px;}
.ui-jqgrid .ui-jqgrid-resize-rtl {float: left;margin: -2px 0px -1px -3px;}
.ui-jqgrid .ui-sort-rtl {left:0px;}
.ui-jqgrid .tree-wrap-ltr {float: left;}
.ui-jqgrid .tree-wrap-rtl {float: right;}
.ui-jqgrid .ui-ellipsis {text-overflow:ellipsis; -moz-binding:url('ellipsis-xbl.xml#ellipsis');}
......@@ -28,7 +28,7 @@
<plugin>
<groupId>com.site.maven.plugins</groupId>
<artifactId>maven-codegen-plugin</artifactId>
<version>1.0.0-a4</version>
<version>1.0.6</version>
<executions>
<execution>
<id>default-cli</id>
......
......@@ -38,6 +38,7 @@ public class Cat {
if (!s_instance.m_initialized) {
try {
s_instance.setContainer(new DefaultPlexusContainer());
s_instance.m_initialized = true;
} catch (PlexusContainerException e) {
throw new RuntimeException("Error when creating Plexus container, "
+ "please make sure the environment was setup correctly!", e);
......@@ -87,6 +88,7 @@ public class Cat {
if (container != null) {
if (!s_instance.m_initialized) {
s_instance.setContainer(container);
s_instance.m_initialized = true;
} else {
throw new RuntimeException("Cat has already been initialized before!");
}
......@@ -102,6 +104,10 @@ public class Cat {
}
}
public static boolean isInitialized() {
return s_instance.m_initialized;
}
// this should be called when a thread ends to clean some thread local data
public static void reset() {
getInstance().m_manager.reset();
......@@ -114,8 +120,6 @@ public class Cat {
}
void setContainer(PlexusContainer container) {
m_initialized = true;
try {
m_manager = (MessageManager) container.lookup(MessageManager.class);
} catch (ComponentLookupException e) {
......
......@@ -66,7 +66,7 @@ public class ComponentsConfigurator extends AbstractResourceConfigurator {
all.add(C(MessageConsumer.class, "dummy", DummyConsumer.class));
all.add(C(MessageConsumer.class, "dump-to-html", DumpToHtmlConsumer.class) //
.req(MessageCodec.class, "html") //
.req(MessageStorage.class, "html") //
.req(MessagePathBuilder.class));
all.add(C(MessageConsumerRegistry.class, DefaultMessageConsumerRegistry.class) //
.req(MessageConsumer.class, new String[] { "dummy" }, "m_consumers"));
......
......@@ -5,6 +5,10 @@ import java.net.UnknownHostException;
import java.util.Stack;
import java.util.UUID;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import com.dianping.cat.Cat;
import com.dianping.cat.configuration.model.entity.Config;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
......@@ -15,7 +19,7 @@ import com.dianping.cat.message.spi.MessageTree;
import com.dianping.cat.message.spi.internal.DefaultMessageTree;
import com.site.lookup.ContainerHolder;
public class DefaultMessageManager extends ContainerHolder implements MessageManager {
public class DefaultMessageManager extends ContainerHolder implements MessageManager, LogEnabled {
private TransportManager m_manager;
// we don't use static modifier since MessageManager is a singleton in
......@@ -37,14 +41,27 @@ public class DefaultMessageManager extends ContainerHolder implements MessageMan
private String m_ipAddress;
private Logger m_logger;
private boolean m_firstMessage = true;
@Override
public void add(Message message) {
getContext().add(this, message);
if (Cat.isInitialized()) {
getContext().add(this, message);
}
}
@Override
public void enableLogging(Logger logger) {
m_logger = logger;
}
@Override
public void end(Transaction transaction) {
getContext().end(this, transaction);
if (Cat.isInitialized()) {
getContext().end(this, transaction);
}
}
void flush(MessageTree tree) {
......@@ -62,11 +79,6 @@ public class DefaultMessageManager extends ContainerHolder implements MessageMan
return m_clientConfig;
}
@Override
public Config getServerConfig() {
return m_serverConfig;
}
Context getContext() {
Context ctx = m_context.get();
......@@ -78,6 +90,11 @@ public class DefaultMessageManager extends ContainerHolder implements MessageMan
}
}
@Override
public Config getServerConfig() {
return m_serverConfig;
}
@Override
public void initializeClient(Config clientConfig) {
if (clientConfig != null) {
......@@ -123,7 +140,12 @@ public class DefaultMessageManager extends ContainerHolder implements MessageMan
@Override
public void start(Transaction transaction) {
getContext().start(transaction);
if (Cat.isInitialized()) {
getContext().start(transaction);
} else if (m_firstMessage){
m_firstMessage = false;
m_logger.warn("CAT client is not enabled because it's not initialized yet");
}
}
static class Context {
......@@ -138,12 +160,12 @@ public class DefaultMessageManager extends ContainerHolder implements MessageMan
m_tree.setDomain(domain);
m_tree.setSessionToken(sessionToken);
m_tree.setRequestToken(requestToken);
Thread thread = Thread.currentThread();
m_tree.setThreadId(Long.toHexString(thread.getId()));
m_tree.setThreadId(thread.getName());
m_tree.setHostName(hostName);
m_tree.setIpAddress(ipAddress);
m_tree.setMessageId(UUID.randomUUID().toString()); // TODO optimize it
......
......@@ -57,13 +57,19 @@ public class StringRope {
@Override
public String toString() {
StringBuilder sb = new StringBuilder(256);
if (m_parts.isEmpty()) {
return "";
} else if (m_parts.size() == 1) {
return m_parts.get(0);
} else {
StringBuilder sb = new StringBuilder(256);
for (String part : m_parts) {
sb.append(part);
}
for (String part : m_parts) {
sb.append(part);
return sb.toString();
}
return sb.toString();
}
public int writeTo(ChannelBuffer buffer, BufferWriter writer) {
......
......@@ -2,7 +2,6 @@ package com.dianping.cat.message.spi.codec;
import org.jboss.netty.buffer.ChannelBuffer;
public class HtmlEncodingBufferWriter implements BufferWriter {
private static byte[] AMP = "&amp;".getBytes();
......@@ -24,17 +23,17 @@ public class HtmlEncodingBufferWriter implements BufferWriter {
if (b == '&') {
buffer.writeBytes(data, offset, i - offset);
buffer.writeBytes(AMP);
count += AMP.length;
count += AMP.length - 1;
offset = i + 1;
} else if (b == '<') {
buffer.writeBytes(data, offset, i - offset);
buffer.writeBytes(LT);
count += LT.length;
count += LT.length - 1;
offset = i + 1;
} else if (b == '>') {
buffer.writeBytes(data, offset, i - offset);
buffer.writeBytes(GT);
count += GT.length;
count += GT.length - 1;
offset = i + 1;
} else if (b == '\n') {
// we want '\n' be output again for better format
......
......@@ -19,11 +19,14 @@ import com.dianping.cat.message.spi.MessageTree;
import com.dianping.cat.message.spi.StringRope;
import com.site.lookup.annotation.Inject;
/**
* Local use only, do not use it over network since it only supports one-way encoding
*/
public class HtmlMessageCodec implements MessageCodec {
private static final String ID = "HT1"; // HTML version 1
@Inject
private BufferWriter m_writer = new HtmlEncodingBufferWriter();
private BufferWriter m_writer;
private BufferHelper m_bufferHelper = new BufferHelper(m_writer);
......@@ -243,9 +246,10 @@ public class HtmlMessageCodec implements MessageCodec {
count += TD1.length;
} else {
String tag = "<td class=\"" + styleClass + "\">";
byte[] bytes = tag.getBytes();
buf.writeBytes(tag.getBytes());
count += tag.length();
buf.writeBytes(bytes);
count += bytes.length;
}
buf.writeBytes(data);
......@@ -273,9 +277,10 @@ public class HtmlMessageCodec implements MessageCodec {
return TR1.length;
} else {
String tag = "<tr class=\"" + styleClass + "\">";
byte[] bytes = tag.getBytes();
buf.writeBytes(tag.getBytes());
return tag.length();
buf.writeBytes(bytes);
return bytes.length;
}
}
......
package com.dianping.cat.message.spi.consumer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import com.dianping.cat.message.spi.MessageCodec;
import com.dianping.cat.message.spi.MessageConsumer;
import com.dianping.cat.message.spi.MessagePathBuilder;
import com.dianping.cat.message.spi.MessageStorage;
import com.dianping.cat.message.spi.MessageTree;
import com.site.lookup.annotation.Inject;
public class DumpToHtmlConsumer implements MessageConsumer, Initializable, LogEnabled {
@Inject
private MessageCodec m_codec;
private MessageStorage m_storage;
@Inject
private MessagePathBuilder m_builder;
......@@ -28,32 +24,7 @@ public class DumpToHtmlConsumer implements MessageConsumer, Initializable, LogEn
@Override
public void consume(MessageTree tree) {
File baseDir = m_builder.getLogViewBaseDir();
File file = new File(baseDir, m_builder.getLogViewPath(tree));
FileOutputStream fos = null;
file.getParentFile().mkdirs();
try {
ChannelBuffer buf = ChannelBuffers.dynamicBuffer(8192);
m_codec.encode(tree, buf);
int length = buf.readInt();
fos = new FileOutputStream(file);
buf.getBytes(buf.readerIndex(), fos, length);
} catch (Exception e) {
throw new RuntimeException(String.format("Error when dumping to HTML file(%s)!", file), e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// ignore it
}
}
}
m_storage.store(tree);
}
@Override
......
......@@ -3,9 +3,15 @@ package com.dianping.cat.message.spi.internal;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
......@@ -15,48 +21,116 @@ import com.dianping.cat.message.spi.MessageStorage;
import com.dianping.cat.message.spi.MessageTree;
import com.site.lookup.annotation.Inject;
public class DefaultMessageStorage implements MessageStorage, LogEnabled {
public class DefaultMessageStorage implements MessageStorage, Initializable, Disposable, LogEnabled {
@Inject
private MessagePathBuilder m_builder;
@Inject
private MessageCodec m_codec;
private WriteJob m_job = new WriteJob();
private Logger m_logger;
@Override
public void dispose() {
m_job.shutdown();
}
@Override
public void enableLogging(Logger logger) {
m_logger = logger;
}
@Override
public void initialize() throws InitializationException {
Thread thread = new Thread(m_job);
thread.setName("Storage write Job");
thread.start();
}
@Override
public String store(MessageTree tree) {
String path = m_builder.getLogViewPath(tree);
File file = new File(m_builder.getLogViewBaseDir(), path);
if (!file.exists()) {
ChannelBuffer buf = ChannelBuffers.dynamicBuffer(8192);
FileOutputStream fos = null;
m_job.append(tree);
return path;
}
class WriteJob implements Runnable {
private BlockingQueue<MessageTree> m_queue = new LinkedBlockingQueue<MessageTree>();
private boolean m_active = true;
public void append(MessageTree tree) {
try {
m_queue.put(tree);
} catch (Exception e) {
m_logger.warn("Error when adding job to queue.", e);
}
}
private void handle(MessageTree tree) {
String path = m_builder.getLogViewPath(tree);
File file = new File(m_builder.getLogViewBaseDir(), path);
if (!file.exists()) {
ChannelBuffer buf = ChannelBuffers.dynamicBuffer(8192);
FileOutputStream fos = null;
file.getParentFile().mkdirs();
try {
fos = new FileOutputStream(file);
m_codec.encode(tree, buf);
file.getParentFile().mkdirs();
int length = buf.readInt();
buf.getBytes(buf.readerIndex(), fos, length);
} catch (IOException e) {
m_logger.error(String.format("Error when writing to file(%s)!", file), e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// ignore it
}
}
}
}
}
@Override
public void run() {
try {
m_codec.encode(tree, buf);
fos = new FileOutputStream(file);
buf.getBytes(buf.readerIndex(), fos, buf.readableBytes());
} catch (IOException e) {
m_logger.error(String.format("Error when writing to file(%s)!", file), e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// ignore it
while (m_active) {
MessageTree tree = m_queue.poll(1000 * 1000L, TimeUnit.NANOSECONDS); // 1
// ms
if (tree != null) {
handle(tree);
}
}
// process the remaining job in the queue
while (!m_active) {
MessageTree tree = m_queue.poll();
if (tree != null) {
handle(tree);
} else {
break;
}
}
} catch (Exception e) {
m_logger.warn("Error when processing job in queue.", e);
}
}
return path;
public void shutdown() {
m_active = true;
}
}
}
......@@ -103,7 +103,7 @@
<implementation>com.dianping.cat.message.spi.consumer.DumpToHtmlConsumer</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.message.spi.MessageCodec</role>
<role>com.dianping.cat.message.spi.MessageStorage</role>
<role-hint>html</role-hint>
</requirement>
<requirement>
......
......@@ -24,6 +24,7 @@ public class HtmlMessageCodecTest {
HtmlMessageCodec codec = new HtmlMessageCodec();
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
codec.setBufferWriter(new HtmlEncodingBufferWriter());
codec.encodeMessage(message, buf, 0, null);
String actual = buf.toString(Charset.forName("utf-8"));
......@@ -34,6 +35,7 @@ public class HtmlMessageCodecTest {
HtmlMessageCodec codec = new HtmlMessageCodec();
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
codec.setBufferWriter(new HtmlEncodingBufferWriter());
codec.encode(tree, buf);
buf.readInt(); // get rid of length
String actual = buf.toString(Charset.forName("utf-8"));
......@@ -90,8 +92,7 @@ public class HtmlMessageCodecTest {
long timestamp = 1325489621987L;
Event event = newEvent("type", "name", timestamp, "0", "here is the data.");
check(event,
"<tr><td>E15:33:41.987</td><td>type</td><td>name</td><td>0</td><td>here is the data.</td></tr>\r\n");
check(event, "<tr><td>E15:33:41.987</td><td>type</td><td>name</td><td>0</td><td>here is the data.</td></tr>\r\n");
}
@Test
......
......@@ -13,7 +13,9 @@ com.dianping.cat.report.page.transaction.Handler.class,
com.dianping.cat.report.page.failure.Handler.class,
com.dianping.cat.report.page.logview.Handler.class
com.dianping.cat.report.page.logview.Handler.class,
com.dianping.cat.report.page.ip.Handler.class
})
public class ReportModule extends AbstractModule {
......
......@@ -5,27 +5,32 @@ import com.site.web.mvc.annotation.ModuleMeta;
public enum ReportPage implements Page {
HOME("home", "home", "Home", true),
HOME("home", "home", "Home", "CAT Home Page.", true),
TRANSACTION("transaction", "t", "Transaction", true),
TRANSACTION("transaction", "t", "Transaction", "CAL summary report for Transactions in current hour.", true),
FAILURE("failure", "f", "Failure", true),
FAILURE("failure", "f", "Failure", "CAL detail report for failure messages in current hour.", true),
LOGVIEW("logview", "m", "Logview", true);
LOGVIEW("logview", "m", "Logview", "CAL log details view for a given message.", false),
IP("ip", "ip", "Top IP List", "Top visited IP list in current hour.", true);
private String m_name;
private String m_path;
private String m_title;
private String m_description;
private boolean m_realPage;
private boolean m_standalone;
private ReportPage(String name, String path, String description, boolean realPage) {
private ReportPage(String name, String path, String title, String description, boolean standalone) {
m_name = name;
m_path = path;
m_title = title;
m_description = description;
m_realPage = realPage;
m_standalone = standalone;
}
public static ReportPage getByName(String name, ReportPage defaultPage) {
......@@ -62,8 +67,12 @@ public enum ReportPage implements Page {
return m_path;
}
public boolean isRealPage() {
return m_realPage;
public String getTitle() {
return m_title;
}
public boolean isStandalone() {
return m_standalone;
}
public ReportPage[] getValues() {
......
......@@ -17,10 +17,8 @@ public class FailureData {
private static final int CURRENT=1;
private static String getFailureJsonDate(FailureReport report) {
DefaultJsonBuilder builder = new DefaultJsonBuilder();
report.accept(builder);
return builder.getString();
public static String getFailureJsonDate(FailureReport report) {
return new DefaultJsonBuilder().buildJson(report);
}
public static String getFailureDataFromMemory(FailureReportAnalyzer analyzer, String domain, String ip) {
......
......@@ -161,6 +161,7 @@ public class Handler implements PageHandler<Context> {
} else {
jsonResult = FailureData.getFailureDataFromMemory(analyzer, domain, ip);
}
model.setJsonResult(jsonResult);
} else {
String baseFilePath = analyzerForPage.getReportPath();
jsonResult =FailureData.getFailureDataFromFile(baseFilePath, file);
......
package com.dianping.cat.report.page.ip;
public enum Action implements com.site.web.mvc.Action {
VIEW("view");
private String m_name;
private Action(String name) {
m_name = name;
}
public static Action getByName(String name, Action defaultAction) {
for (Action action : Action.values()) {
if (action.getName().equals(name)) {
return action;
}
}
return defaultAction;
}
@Override
public String getName() {
return m_name;
}
}
package com.dianping.cat.report.page.ip;
import com.dianping.cat.report.ReportContext;
public class Context extends ReportContext<Payload> {
}
package com.dianping.cat.report.page.ip;
public class DisplayModel {
private String m_address;
private int m_lastOne;
private int m_lastFive;
private int m_lastFifteen;
public DisplayModel(String address) {
m_address = address;
}
public String getAddress() {
return m_address;
}
public int getLastFifteen() {
return m_lastFifteen;
}
public int getLastFive() {
return m_lastFive;
}
public int getLastOne() {
return m_lastOne;
}
public void process(int current, int minute, int count) {
if (current == minute) {
m_lastOne += count;
m_lastFive += count;
m_lastFifteen += count;
} else if (current < minute) {
// ignore it
} else if (current - 5 < minute) {
m_lastFive += count;
m_lastFifteen += count;
} else if (current - 15 < minute) {
m_lastFifteen += count;
}
}
}
\ No newline at end of file
package com.dianping.cat.report.page.ip;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import com.dianping.cat.consumer.RealtimeConsumer;
import com.dianping.cat.consumer.ip.IpAnalyzer;
import com.dianping.cat.consumer.ip.model.entity.Ip;
import com.dianping.cat.consumer.ip.model.entity.IpReport;
import com.dianping.cat.consumer.ip.model.entity.Period;
import com.dianping.cat.consumer.ip.model.transform.BaseVisitor;
import com.dianping.cat.message.spi.MessageConsumer;
import com.dianping.cat.report.ReportPage;
import com.site.lookup.annotation.Inject;
import com.site.web.mvc.PageHandler;
import com.site.web.mvc.annotation.InboundActionMeta;
import com.site.web.mvc.annotation.OutboundActionMeta;
import com.site.web.mvc.annotation.PayloadMeta;
public class Handler implements PageHandler<Context> {
@Inject
private JspViewer m_jspViewer;
@Inject(type = MessageConsumer.class, value = "realtime")
private RealtimeConsumer m_consumer;
@Override
@PayloadMeta(Payload.class)
@InboundActionMeta(name = "ip")
public void handleInbound(Context ctx) throws ServletException, IOException {
// display only, no action here
}
@Override
@OutboundActionMeta(name = "ip")
public void handleOutbound(Context ctx) throws ServletException, IOException {
Model model = new Model(ctx);
model.setAction(Action.VIEW);
model.setPage(ReportPage.IP);
IpAnalyzer analyzer = (IpAnalyzer) m_consumer.getCurrentAnalyzer("ip");
IpReport report;
if (analyzer != null) {
Payload payload = ctx.getPayload();
String domain = payload.getDomain();
List<String> domains = analyzer.getDomains();
if (domain == null && domains.size() > 0) {
domain = domains.get(0);
payload.setDomain(domain);
}
report = analyzer.generate(domain);
model.setDomains(domains);
} else {
report = new IpReport();
}
Calendar cal = Calendar.getInstance();
int minute = cal.get(Calendar.MINUTE);
Map<String, DisplayModel> models = new HashMap<String, DisplayModel>();
DisplayModelBuilder builder = new DisplayModelBuilder(models, minute);
report.accept(builder); // prepare display model
List<DisplayModel> displayModels = new ArrayList<DisplayModel>(models.values());
Collections.sort(displayModels, new Comparator<DisplayModel>() {
@Override
public int compare(DisplayModel m1, DisplayModel m2) {
return m2.getLastFifteen() - m1.getLastFifteen(); // desc
}
});
model.setReport(report);
model.setDisplayModels(displayModels);
m_jspViewer.view(ctx, model);
}
static class DisplayModelBuilder extends BaseVisitor {
private int m_minute;
private Map<String, DisplayModel> m_models;
private Period m_period;
public DisplayModelBuilder(Map<String, DisplayModel> models, int minute) {
m_models = models;
m_minute = minute;
}
@Override
public void visitIp(Ip ip) {
String address = ip.getAddress();
DisplayModel model = m_models.get(address);
if (model == null) {
model = new DisplayModel(address);
m_models.put(address, model);
}
model.process(m_minute, m_period.getMinute(), ip.getCount());
}
@Override
public void visitPeriod(Period period) {
m_period = period;
super.visitPeriod(period);
}
}
}
package com.dianping.cat.report.page.ip;
public enum JspFile {
VIEW("/jsp/report/ip.jsp"),
;
private String m_path;
private JspFile(String path) {
m_path = path;
}
public String getPath() {
return m_path;
}
}
package com.dianping.cat.report.page.ip;
import com.dianping.cat.report.ReportPage;
import com.site.web.mvc.view.BaseJspViewer;
public class JspViewer extends BaseJspViewer<ReportPage, Action, Context, Model> {
@Override
protected String getJspFilePath(Context ctx, Model model) {
Action action = model.getAction();
switch (action) {
case VIEW:
return JspFile.VIEW.getPath();
}
throw new RuntimeException("Unknown action: " + action);
}
}
package com.dianping.cat.report.page.ip;
import java.util.List;
import com.dianping.cat.consumer.ip.model.entity.IpReport;
import com.dianping.cat.report.ReportPage;
import com.site.web.mvc.ViewModel;
public class Model extends ViewModel<ReportPage, Action, Context> {
private IpReport m_report;
private List<DisplayModel> m_displayModels;
private List<String> m_domains;
public Model(Context ctx) {
super(ctx);
}
@Override
public Action getDefaultAction() {
return Action.VIEW;
}
public List<DisplayModel> getDisplayModels() {
return m_displayModels;
}
public List<String> getDomains() {
return m_domains;
}
public IpReport getReport() {
return m_report;
}
public String getReportInJson() {
return String.format(IpReport.JSON, m_report);
}
public void setDisplayModels(List<DisplayModel> models) {
m_displayModels = models;
}
public void setDomains(List<String> domains) {
m_domains = domains;
}
public void setReport(IpReport report) {
m_report = report;
}
}
package com.dianping.cat.report.page.ip;
import com.dianping.cat.report.ReportPage;
import com.site.web.mvc.ActionContext;
import com.site.web.mvc.ActionPayload;
import com.site.web.mvc.payload.annotation.FieldMeta;
public class Payload implements ActionPayload<ReportPage, Action> {
private ReportPage m_page;
@FieldMeta("op")
private Action m_action;
@FieldMeta("domain")
private String m_domain;
@Override
public Action getAction() {
return m_action;
}
public String getDomain() {
return m_domain;
}
@Override
public ReportPage getPage() {
return m_page;
}
public void setAction(Action action) {
m_action = action;
}
public void setDomain(String domain) {
m_domain = domain;
}
@Override
public void setPage(String page) {
m_page = ReportPage.getByName(page, ReportPage.IP);
}
@Override
public void validate(ActionContext<?> ctx) {
}
}
......@@ -14,7 +14,12 @@ import com.site.web.mvc.PageHandler;
import com.site.web.mvc.annotation.InboundActionMeta;
import com.site.web.mvc.annotation.OutboundActionMeta;
import com.site.web.mvc.annotation.PayloadMeta;
import com.site.web.mvc.payload.ParameterProvider;
/**
* @author sean.wang
* @since Feb 6, 2012
*/
public class Handler implements PageHandler<Context> {
@Inject
private JspViewer m_jspViewer;
......@@ -37,11 +42,12 @@ public class Handler implements PageHandler<Context> {
model.setAction(Action.VIEW);
model.setPage(ReportPage.TRANSACTION);
TransactionReportAnalyzer analyzer = (TransactionReportAnalyzer) m_consumer
.getCurrentAnalyzer("transaction");
TransactionReportAnalyzer analyzer = (TransactionReportAnalyzer) m_consumer.getCurrentAnalyzer("transaction");
if (analyzer != null) {
model.setReport(analyzer.generate(ctx.getRequestContext().getParameterProvider().getParameter("domain")));
ParameterProvider provider = ctx.getRequestContext().getParameterProvider();
model.setReport(analyzer.generate(provider.getParameter("domain")));
model.setType(provider.getParameter("type"));
} else {
model.setReport(new TransactionReport("none"));
}
......
......@@ -7,6 +7,8 @@ import com.site.web.mvc.ViewModel;
public class Model extends ViewModel<ReportPage, Action, Context> {
private TransactionReport m_report;
private String type;
public Model(Context ctx) {
super(ctx);
......@@ -22,13 +24,18 @@ public class Model extends ViewModel<ReportPage, Action, Context> {
}
public String getReportInJson() {
DefaultJsonBuilder builder = new DefaultJsonBuilder();
m_report.accept(builder);
return builder.getString();
return new DefaultJsonBuilder().buildJson(m_report);
}
public void setReport(TransactionReport report) {
m_report = report;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
......@@ -13,6 +13,8 @@ public class NavigationBar {
ReportPage.TRANSACTION,
ReportPage.IP,
ReportPage.LOGVIEW
};
......
......@@ -77,6 +77,9 @@
<requirement>
<role>long</role>
</requirement>
<requirement>
<role>int</role>
</requirement>
<requirement>
<role>java.util.List</role>
</requirement>
......@@ -119,5 +122,23 @@
<role>com.dianping.cat.report.page.logview.JspViewer</role>
<implementation>com.dianping.cat.report.page.logview.JspViewer</implementation>
</component>
<component>
<role>com.dianping.cat.report.page.ip.Handler</role>
<implementation>com.dianping.cat.report.page.ip.Handler</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.report.page.ip.JspViewer</role>
</requirement>
<requirement>
<role>com.dianping.cat.message.spi.MessageConsumer</role>
<role-hint>realtime</role-hint>
<field-name>m_consumer</field-name>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.report.page.ip.JspViewer</role>
<implementation>com.dianping.cat.report.page.ip.JspViewer</implementation>
</component>
</components>
</plexus>
<?xml version="1.0" encoding="UTF-8"?>
<wizard package="com.dianping.cat" webres="true">
<module name="report" path="r">
<page name="home" description="Home" default="true" />
<page name="transaction" path="t" description="Transaction" />
<page name="failure" path="f" description="Failure" />
<page name="logview" path="m" description="Logview" />
<page name="home" title="Home" default="true">
<description>CAT Home Page.</description>
</page>
<page name="transaction" path="t" title="Transaction">
<description>CAL summary report for Transactions in current hour.</description>
</page>
<page name="failure" path="f" title="Failure">
<description>CAL detail report for failure messages in current hour.</description>
</page>
<page name="logview" path="m" title="Logview" standalone="false">
<description>CAL log details view for a given message.</description>
</page>
<page name="ip" title="Top IP List">
<description>Top visited IP list in current hour.</description>
</page>
</module>
</wizard>
......@@ -15,6 +15,10 @@
<name>body</name>
<path>/WEB-INF/tags/body.tag</path>
</tag-file>
<tag-file>
<name>report</name>
<path>/WEB-INF/tags/report.tag</path>
</tag-file>
<function>
<description>Build form action for given id</description>
<name>action</name>
......
<%@ tag trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.ebay.com/webres"%>
<jsp:useBean id="navBar" class="com.dianping.garden.view.NavigationBar" scope="page"/>
......@@ -5,11 +6,11 @@
<res:bean id="res"/>
<html>
<head>
<title>Garden - ${model.page.description}</title>
<title>CAT - ${model.page.description}</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<res:cssSlot id="head-css"/>
<res:jsSlot id="head-js"/>
<res:useCss value='${res.css.local.default_css}' target="head-css"/>
<res:useCss value='${res.css.local.body_css}' target="head-css"/>
</head>
<body>
<h1>
......@@ -17,8 +18,11 @@
</h1>
<ul class="tabs">
<c:forEach var="page" items="${navBar.visiblePages}">
<c:if test="${page.realPage}">
<li ${model.page.name == page.name ? 'class="selected"' : ''}><a href="${model.webapp}/${page.moduleName}/${page.path}">${page.description}</a></li>
<c:if test="${page.standalone}">
<li ${model.page.name == page.name ? 'class="selected"' : ''}><a href="${model.webapp}/${page.moduleName}/${page.path}">${page.title}</a></li>
</c:if>
<c:if test="${not page.standalone and model.page.name == page.name}">
<li class="selected">${page.title}</li>
</c:if>
</c:forEach>
</ul>
......
<%@ tag trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="a" uri="/WEB-INF/app.tld"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.ebay.com/webres"%>
<%@ attribute name="title"%>
<%@ attribute name="timestamp"%>
<%@ attribute name="domain" fragment="true"%>
<%@ attribute name="nav" fragment="true"%>
<%@ attribute name="subtitle" fragment="true"%>
<a:body>
<res:useCss value='${res.css.local.report_css}' target="head-css" />
<div class="report">
<table class="header">
<tr>
<td class="title">${title}</td>
<td class="timestamp">Generated: ${timestamp}</td>
</tr>
</table>
<table class="navbar">
<tr>
<td class="domain"><jsp:invoke fragment="domain"/></td>
<td class="nav"><jsp:invoke fragment="nav"/></td>
</tr>
<tr>
<td class="subtitle"><jsp:invoke fragment="subtitle"/></td>
</tr>
</table>
<br />
<jsp:doBody />
<br />
<table class="footer">
<tr>
<td>[ end ]</td>
</tr>
</table>
</div>
</a:body>
\ No newline at end of file
......@@ -51,6 +51,13 @@
<tag-class>com.ebay.webres.taglib.basic.UseCssTagHandler</tag-class>
<body-content>JSP</body-content>
<attribute>
<description><![CDATA[Set the css value with EL or a css ref.]]></description>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Identify whether the link URL is secure or not.]]></description>
<name>secure</name>
<required>false</required>
......@@ -72,13 +79,6 @@
<type>java.lang.String</type>
</attribute>
<attribute>
<description><![CDATA[Set the css value with EL or a css ref.]]></description>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Target placement for this css resource to render]]></description>
<name>target</name>
<required>false</required>
......@@ -114,18 +114,18 @@
<tag-class>com.ebay.webres.taglib.basic.SetTagHandler</tag-class>
<body-content>JSP</body-content>
<attribute>
<description><![CDATA[The name.]]></description>
<name>id</name>
<description><![CDATA[The value]]></description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[The value]]></description>
<name>value</name>
<description><![CDATA[The name.]]></description>
<name>id</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
<type>java.lang.String</type>
</attribute>
<dynamic-attributes>false</dynamic-attributes>
</tag>
......@@ -135,6 +135,13 @@
<tag-class>com.ebay.webres.taglib.basic.UseJsTagHandler</tag-class>
<body-content>JSP</body-content>
<attribute>
<description><![CDATA[Set the js value with EL or a js ref.]]></description>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Identify whether the link URL is secure or not.]]></description>
<name>secure</name>
<required>false</required>
......@@ -156,13 +163,6 @@
<type>java.lang.String</type>
</attribute>
<attribute>
<description><![CDATA[Set the js value with EL or a js ref.]]></description>
<name>value</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Target placement for this js resource to render]]></description>
<name>target</name>
<required>false</required>
......@@ -177,6 +177,13 @@
<tag-class>com.ebay.webres.taglib.basic.LinkTagHandler</tag-class>
<body-content>JSP</body-content>
<attribute>
<description><![CDATA[The value for link, could be a expression or a link ref.]]></description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Identify whether the link URL is secure or not.]]></description>
<name>secure</name>
<required>false</required>
......@@ -190,13 +197,6 @@
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
<attribute>
<description><![CDATA[The value for link, could be a expression or a link ref.]]></description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<dynamic-attributes>true</dynamic-attributes>
</tag>
<tag>
......@@ -205,6 +205,13 @@
<tag-class>com.ebay.webres.taglib.basic.ImageTagHandler</tag-class>
<body-content>JSP</body-content>
<attribute>
<description><![CDATA[The value for image, could be a expression or a image path.]]></description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<attribute>
<description><![CDATA[Identify whether the image URL is secure or not.]]></description>
<name>secure</name>
<required>false</required>
......@@ -225,13 +232,6 @@
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
<attribute>
<description><![CDATA[The value for image, could be a expression or a image path.]]></description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Object</type>
</attribute>
<dynamic-attributes>true</dynamic-attributes>
</tag>
<tag>
......
body {
font-family: arial, helvetica, sans-serif;
font-size: small;
background: white;
color: black;
margin: 4px;
padding: 0;
}
html { margin: 0 }
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
ul.tabs {
border-bottom: 1px solid gray;
list-style-type: none;
position: relative;
padding: 0em;
padding-top: 0.4em;
padding-bottom: 0.4em;
}
.tabs li {
display: inline;
margin: 0em 0.4em 0em 0.4em;
padding: 0.4em 0.4em 0.4em 0.4em;
overflow: hidden;
border-top: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
}
.tabs li.selected {
background: #ccddff;
border-bottom: 1px solid white;
}
tr.head {
background-color: #e8e8e8;
}
tr.strip {
background-color: #f2f2f2;
}
tr.head th {
background-color: #f2f2f2;
border-bottom: 1px solid #c4c4c4;
}
tr th {
background-color: #f2f2f2;
}
......@@ -25,6 +25,7 @@ ul.tabs {
list-style-type: none;
position: relative;
padding: 0em;
padding-top: 0.4em;
padding-bottom: 0.4em;
}
......
.ip-table .odd td {
background-color: #eee;
font-size: small;
text-align: center;
}
.ip-table .even td {
background-color: white;
font-size: small;
text-align: center;
}
.report .header {
background: orange;
color: white;
font-weight: bold;
border-bottom: solid black 1px;
width: 100%;
}
.report .header .title {
font-weight: bold;
}
.report .header .timestamp {
white-space: nowrap;
width: 200px;
}
.report .navbar {
background: lightblue;
font-weight: bold;
border-bottom: solid black 1px;
width: 100%;
}
.report .navbar .domain {
text-align: left;
font-size: small;
font-weight: bold;
}
.report .navbar .domain A {
text-decoration: none;
color: blue;
}
.report .navbar .domain .current {
color: black;
}
.report .navbar .domain A:hover {
color: yellow;
}
.report .navbar .nav {
text-align: right;
font-size: small;
font-weight: bold;
}
.report .navbar .nav A {
text-decoration: none;
color: blue;
}
.report .navbar .nav A:hover {
color: yellow;
}
.report .footer {
background: orange;
color: white;
font-weight: bold;
border-top: solid black 1px;
border-bottom: solid black 1px;
width: 100%;
text-align: center;
}
\ No newline at end of file
var tabledata = [];
$(function(){
var types = data["types"];
for (i in types) {
var type = types[i];
var sampleid = type.successMessageUrl != null ? type.successMessageUrl : type.failMessageUrl;
var stat = "" + type.min + "/" + type.max + "/" + type.avg + "/" + type.std;
tabledata.push({"type":type.id, "total":type.totalCount, "fail":type.failCount, "failPercent":type.failPercent, "sample":"<a href=\"/cat/r/m/"+sampleid+"\" target=\"_blank\">link</a>", "stat":stat});
}
var types = data["types"];
var nowdomain = data["domain"];
if(nowtype != "") {
var names = types[nowtype]["names"];
for (i in names) {
var name = names[i];
var sampleurl = name.failMessageUrl != null ? "<a href=\"m/"+name.failMessageUrl+"\">fail</a>" : "<a href=\"m/"+name.successMessageUrl+"\">success</a>";
var stat = "" + name.min + "/" + name.max + "/" + name.avg + "/" + name.std;
tabledata.push({"name":name.id, "total":name.totalCount, "fail":name.failCount, "failPercent":name.failPercent, "sample":sampleurl, "stat":stat});
}
} else {
for (i in types) {
var type = types[i];
var typeurl = "<a href=\"t?domain=" + nowdomain + "&type=" + type.id + "\">" + type.id + "</a>";
var sampleurl = type.failMessageUrl != null ? "<a href=\"m/"+type.failMessageUrl+"\">fail</a>" : "<a href=\"m/"+type.successMessageUrl+"\">success</a>";
var stat = "" + type.min + "/" + type.max + "/" + type.avg + "/" + type.std;
tabledata.push({"type":typeurl, "total":type.totalCount, "fail":type.failCount, "failPercent":type.failPercent, "sample":sampleurl, "stat":stat});
}
}
}
);
);
domainLink = function(domain, now){
if(domain == now) {
return "[ <a style=\"background-color: rgb(255, 204, 0);\" href=\"t?domain="+domain+"\">"+domain+"</a> ]";
} else {
return "[ <a href=\"t?domain="+domain+"\">"+domain+"</a> ]";
}
};
$(function()
{
domainlinks = 'Domains ';
$.each(data.domains, function(i, t){domainlinks += "[ <a href=\"/cat/r/t?domain="+t+"\">"+t+"</a> ]"});
$("#domainlist").html(domainlinks);
$("#gridTable").jqGrid({
datatype: "local",
colNames:['Type', 'Total Count', 'Fail Count', 'Failure%', 'Sample Link', 'Min/Max/Avg/Std(ms)'],
colModel:[
{name:'type', index:'type', width:200},
{name:'total', index:'total', width:100, sorttype:"int", align:'right'},
{name:'fail', index:'fail', width:100, sorttype:"int", align:'right'},
{name:'failPercent', index:'failPercent', width:100, sorttype:"float", align:'center'},
{name:'sample', index:'sample', width:200, sortable:false},
{name:'stat', width:200, sortable:false}
],
sortname:'type',
sortorder:'asc',
caption: "Domain " + data["domain"] + " Transaction Summary",
height: '100%',
autowidth: true,
loadComplete: function() {
$("#gridTable").setGridHeight('auto');
}
}).navGrid('#pager2',{edit:false,add:false,del:false});
var domainlinks = 'Domains: ';
var nowdomain = data["domain"];
$.each(data.domains, function(i, t){domainlinks += domainLink(t, nowdomain)});
$("#domainlist").html(domainlinks);
$("#reporttitle").html("Transaction Report - Domain:" + nowdomain);
var grid = $("#gridtable");
var colnames;
var colmodels;
if(nowtype == "") {
colnames = ['Type', 'Total Count', 'Fail Count', 'Failure%', 'Sample Link', 'Min/Max/Avg/Std(ms)'];
colmodels = [
{name:'type', index:'type', align:'center'},
{name:'total', index:'total', sorttype:"int", align:'center'},
{name:'fail', index:'fail', sorttype:"int", align:'center'},
{name:'failPercent', index:'failPercent', sorttype:"float", align:'center'},
{name:'sample', index:'sample', sortable:false, align:'center'},
{name:'stat', sortable:false, align:'center',width:200}
];
} else {
colnames = ['Name', 'Total Count', 'Fail Count', 'Failure%', 'Sample Link', 'Min/Max/Avg/Std(ms)'];
colmodels = [
{name:'name', index:'name', align:'center'},
{name:'total', index:'total', sorttype:"int", align:'center'},
{name:'fail', index:'fail', sorttype:"int", align:'center'},
{name:'failPercent', index:'failPercent', sorttype:"float", align:'center'},
{name:'sample', index:'sample', sortable:false, align:'center'},
{name:'stat', sortable:false, align:'center',width:200}
];
}
grid.jqGrid({
"defaults" : {
//shrinkToFit:true,
//forceFit:true,
},
"datatype": "local",
"colNames":colnames,
"colModel":colmodels,
"sortname":'type',
"sortorder":'asc',
"caption": "",
"height": '100%',
"autowidth": true,
"loadComplete": function() {
grid.setGridHeight('auto');
//grid.setGridWidth('auto');
}
}).navGrid('#pager2',{edit:false,add:false,del:false});
var grid = $("#gridTable");
for(var i=0;i<=tabledata.length;i++) {
grid.jqGrid('addRowData',i+1,tabledata[i]);
}
}
$("#gview_gridtable > .ui-jqgrid-titlebar").hide()
$(function(){
$(window).resize(function(){
$("#gridTable").setGridWidth($(window).width()*0.99);
});
});
//$(function(){
// $(window).resize(function(){
// $("#gridTable").setGridWidth($(window).width()*0.99);
// });
//});
}
);
\ No newline at end of file
<%@ page contentType="text/html; charset=utf-8" trimDirectiveWhitespaces="true"%>
<%@ taglib prefix="a" uri="/WEB-INF/app.tld"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.ebay.com/webres"%>
<jsp:useBean id="ctx" type="com.dianping.cat.report.page.ip.Context" scope="request" />
<jsp:useBean id="payload" type="com.dianping.cat.report.page.ip.Payload" scope="request" />
<jsp:useBean id="model" type="com.dianping.cat.report.page.ip.Model" scope="request" />
<a:report title="Hot IP Report" timestamp="2012-02-07">
<jsp:attribute name="domain">
<div class="domain">
<c:forEach var="domain" items="${model.domains}">
&nbsp;[
<c:choose>
<c:when test="${payload.domain eq domain}"><a href="?domain=${domain}" class="current">&nbsp;${domain}&nbsp;</a></c:when>
<c:otherwise><a href="?domain=${domain}">&nbsp;${domain}&nbsp;</a></c:otherwise>
</c:choose>
]&nbsp;
</c:forEach>
</div>
</jsp:attribute>
<jsp:attribute name="nav">
[ <a href="">-1d</a> ] [ <a href="">-2h</a> ] [ <a href="">-1h</a> ] [ <a href="">+1h</a> ] [ <a href="">+2h</a> ] [ <a href="">+1d</a> ]
</jsp:attribute>
<jsp:body>
<res:useCss value='${res.css.local.ip_css}' target="head-css"/>
<table class="ip-table">
<tr><th>IP</th><th>last 1 min</th><th>last 5 mins</th><th>last 15 mins</th></tr>
<c:forEach var="m" items="${model.displayModels}" varStatus="status">
<tr class="${status.index mod 2 != 0 ? 'odd' : 'even'}">
<td>${m.address}</td>
<td>${m.lastOne}</td>
<td>${m.lastFive}</td>
<td>${m.lastFifteen}</td>
</tr>
</c:forEach>
</table>
</jsp:body>
</a:report>
......@@ -8,7 +8,6 @@
<a:body>
<res:useCss value='${res.css.local.default_css}' target="head-css"/>
<res:useCss value='${res.css.local.logview_css}' target="head-css"/>
<c:choose>
......
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="a" uri="/WEB-INF/app.tld"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="res" uri="http://www.ebay.com/webres"%>
<jsp:useBean id="ctx"
type="com.dianping.cat.report.page.transaction.Context" scope="request" />
......@@ -11,6 +12,7 @@
<a:body>
<res:useCss value='${res.css.local.default_css}' target="head-css" />
<res:useCss value='${res.css.local.style_css}' target="head-css" />
<res:useCss value='${res.css.local.jquery_css}' target="head-css" />
<res:useCss value='${res.css.local.jqgrid_css}' target="head-css" />
......@@ -21,20 +23,30 @@
<script type="text/javascript">
var data = ${model.reportInJson};
var nowtype = "${model.type}";
</script>
<table width="100%" border="0" cellpadding="6" cellspacing="0"
class="fancy-header">
<tbody>
<tr>
<td id="reporttitle" nowrap=""></td>
<td width="100%" align="right" nowrap=""></td>
</tr>
</tbody>
</table>
<table width="100%" border="0" cellpadding="6" cellspacing="0"
class="navbar">
<tbody>
<tr>
<td id="domainlist" nowrap="nowrap" align="left" class="seealso">
</td>
</tr>
</tbody>
</table>
<table id="gridTable"></table>
<div id="gridPager"></div>
</table>
<table id="gridtable"></table>
<div id="gridpager"></div>
<res:useJs value="${res.js.local.transaction_js}" target="bottom-js" />
......
......@@ -4,10 +4,13 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import com.dianping.cat.report.page.ip.DisplayModelTest;
@RunWith(Suite.class)
@SuiteClasses({
// add test classes here
/* .report.page.ip */
DisplayModelTest.class
})
public class AllTests {
......
......@@ -36,11 +36,6 @@ public class SimpleServer extends SimpleServerSupport {
JettyTestSupport.startServer(new SimpleServer());
}
@Override
protected File getWarRoot() {
return new File("src/main/webapp");
}
public static void main(String[] args) throws Exception {
SimpleServer server = new SimpleServer();
......@@ -70,19 +65,16 @@ public class SimpleServer extends SimpleServerSupport {
}
@Override
protected void postConfigure(Context ctx) {
ServletHolder holder = new ServletHolder(s_mvc);
ctx.addServlet(new ServletHolder(s_cat), "/s/*");
ctx.addServlet(holder, "/");
ctx.addServlet(holder, "/r/*");
ctx.addFilter(GzipFilter.class, "/r/*", Handler.ALL);
super.postConfigure(ctx);
protected String getContextPath() {
return "/cat";
}
@Override
protected String getContextPath() {
return "/cat";
protected File getScratchDir() {
File work = new File(System.getProperty("java.io.tmpdir", "."), "Cat");
work.mkdirs();
return work;
}
@Override
......@@ -90,6 +82,22 @@ public class SimpleServer extends SimpleServerSupport {
return 2281;
}
@Override
protected File getWarRoot() {
return new File("src/main/webapp");
}
@Override
protected void postConfigure(Context ctx) {
ServletHolder holder = new ServletHolder(s_mvc);
ctx.addServlet(new ServletHolder(s_cat), "/s/*");
ctx.addServlet(holder, "/");
ctx.addServlet(holder, "/r/*");
ctx.addFilter(GzipFilter.class, "/r/*", Handler.ALL);
super.postConfigure(ctx);
}
@Test
public void startServer() throws Exception {
// open the page in the default browser
......@@ -118,15 +126,6 @@ public class SimpleServer extends SimpleServerSupport {
}
}
@Override
public PlexusContainer getContainer() {
return super.getContainer();
}
public void setServerPort(int serverPort) {
m_serverPort = serverPort;
}
public void display(String requestUri) throws Exception {
StringBuilder sb = new StringBuilder(256);
BrowserManager manager = lookup(BrowserManager.class);
......@@ -140,6 +139,11 @@ public class SimpleServer extends SimpleServerSupport {
}
}
@Override
public PlexusContainer getContainer() {
return super.getContainer();
}
@Override
public <T> T lookup(Class<T> role) throws Exception {
return super.lookup(role);
......@@ -149,5 +153,9 @@ public class SimpleServer extends SimpleServerSupport {
public <T> T lookup(Class<T> role, Object roleHint) throws Exception {
return super.lookup(role, roleHint);
}
public void setServerPort(int serverPort) {
m_serverPort = serverPort;
}
}
}
package com.dianping.cat.report.page.ip;
import junit.framework.Assert;
import org.junit.Test;
public class DisplayModelTest {
private void check(DisplayModel model, int time, int count, int lastOne, int lastFive, int lastFifteen) {
model.process(0, time, count);
Assert.assertEquals("Last one", lastOne, model.getLastOne());
Assert.assertEquals("Last five", lastFive, model.getLastFive());
Assert.assertEquals("Last fifteen", lastFifteen, model.getLastFifteen());
}
@Test
public void test() {
DisplayModel model = new DisplayModel("localhost");
check(model, 1, 1, 0, 0, 0);
check(model, 0, 1, 1, 1, 1);
check(model, -1, 2, 1, 3, 3);
check(model, -3, 2, 1, 5, 5);
check(model, -5, 2, 1, 5, 7);
check(model, -10, 2, 1, 5, 9);
check(model, -14, 2, 1, 5, 11);
check(model, -15, 2, 1, 5, 11);
check(model, 1, 2, 1, 5, 11);
}
}
......@@ -167,7 +167,7 @@ org.eclipse.jdt.core.compiler.compliance=1.6
<plugin>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.13</version>
<version>2.8</version>
</plugin>
</plugins>
</pluginManagement>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册