Skip to content

Commit 5d5547b

Browse files
author
Jeffrey Schmidt
committed
* Updated documentation
* Changed naming to reflect StatsAgg 1.2 (final release) * Changed 'one time' alert suspensions -- the duration is no longer limited to 1440 minutes * Updated Datatables
1 parent 6b89ffd commit 5d5547b

File tree

19 files changed

+3619
-3677
lines changed

19 files changed

+3619
-3677
lines changed

ChangeLog.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
StatsAgg 1.2 - released 2015-xx-xx
1+
StatsAgg 1.3 - released 2015-xx-xx
2+
3+
4+
StatsAgg 1.2 - released 2015-04-27
25
* Performance & memory utilization improvements -- most noticeable under high load scenarios
3-
* Added a new OpenTSDB HTTP listener. By default, it will listen on "http://statsagg-hostname:4243"
6+
* Added a new OpenTSDB HTTP listener. By default, it will listen on "http://statsagg-hostname.com:4243"
47
This listener operates outside of the Tomcat container & does not have an application context.
58
This is now the recommended way to get metrics into OpenTSDB via HTTP. The Tomcat listener (same port/context as the WebUI) is still supported, but not recommended.
6-
* Added support for OpenTSDB compression on metric-sending
9+
* Added support for reading OpenTSDB metrics that were sent with gzip compression
710
* Added support for StatsD histograms
811
* Added Support for sample-rates on StatsD timers
912
* Tweaks to many WebUI pages
1013
* Friendly messages when page input parameters aren't valid.
1114
* Applied formatting to the list of email addresses in 'Notification Groups' & 'Notification Group Details'
1215
* WebUI -- Added support for doing a search on a table based off a uri parameter. Allows immediate filtering of the table on page load. Applies to all tables.
16+
* 'One time' alert suspensions are now allowed to suspend an alert indefinitely. Previously they were limited to 24 hours.
1317
* Minor OpenTSDB 'send previous value' improvements
1418
* Lowered the thread priority of alert-routine threads
1519
* Minor security improvements

dev/Todo.txt

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
StatsAgg 1.2
2-
* Retest 'resend previous value' for all formats
3-
* Document example config comparison for statsd histogram
4-
5-
Short/Medium term
1+
StatsAgg 1.3
2+
* Making saving StatsD gauges to the database optional
3+
* Last received metric in WebUI
4+
* Alert associations in WebUI Metric Groups table
65
* More intelligent alert & metric-group alterations. Don't clear/reset if only modifying name/description/etc.
6+
* Convert 'Alert Suspension Details' page into panel-based UI
7+
* Link to 'Triggered' alerts in 'Alert Details'
8+
* Multi-thread StatsD aggregation routine
9+
* Advanced options
10+
* Maximum concurrently running output-threads
11+
* Output-thread timeout
12+
13+
Short/Medium term
714
* Apply column-sort to WebUI tables via parameter in URI
15+
* Incoming metric rate limits
816
* View application config in WebUI
9-
* Last received metric in WebUI
10-
* Alert associations in Metric Groups table
11-
* Convert 'Alert Suspension Details' page into panel-based UI
1217
* OpenTSDB -- send back a list of 'metrics with errors' on HTTP requests with the 'details' parameter
1318
* StatsD forwarder
1419
* Control what StatsD 'timer' fields are outputted (so people can ignore the more useless ones)
1520
* Advanced options
1621
* New application config option -- limit metric results # in WebUI
17-
* Maximum concurrently running output-threads
18-
* Output-thread timeout
1922
* Cleanup metrics after... (currently hardcoded to 24hrs)
2023
* Debug mode for "details" pages (include additional details)
2124
* Manual injection of metrics via a new servlet w/ a WebUI component

docs/component-diagram.png

-19.3 KB
Loading

docs/manual.pdf

14.6 KB
Binary file not shown.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>com.pearson.StatsAgg</groupId>
66
<artifactId>StatsAgg</artifactId>
7-
<version>1.2-beta</version>
7+
<version>1.2</version>
88
<packaging>war</packaging>
99
<name>StatsAgg</name>
1010

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Detailed installation instructions can be found in the [StatsAgg user manual](./
8989
* [Java Metrics](https://dropwizard.github.io/metrics)
9090
* [CollectD](https://collectd.org/)
9191
* [tcollector](https://github.com/OpenTSDB/tcollector/)
92+
* [scollector](https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector)
9293
* StatsPoller -- a Pearson-developed metrics collection agent for servers (to be released sometime in 2015).
9394
* Anything that can output in Graphite, StatsD, or OpenTSDB format
9495

@@ -101,7 +102,7 @@ Detailed information about StatsAgg's metric format support, including examples,
101102

102103
## Technology
103104
* StatsAgg is a Java 1.7 based webapp. It compiles into a war file, and is intended to be deployed into Apache Tomcat 7+.
104-
* StatsAgg uses a database for storing things like 'StatsD gauge values', alert definitions & statuses, metric group definitions, etc. The database technology can be Apache Derby Embedded, or MySQL 5.6+.
105+
* StatsAgg uses a database for storing things like 'StatsD gauge values', alert definitions & statuses, metric group definitions, etc. The database technology can be Apache Derby Embedded or MySQL 5.6+.
105106
* StatsAgg can run on almost any modern OS. Windows, Linux, etc.
106107

107108
<br>
@@ -110,7 +111,6 @@ Detailed information about StatsAgg's metric format support, including examples,
110111
* StatsAgg only supports running in a single-server configuration.
111112
* While this is a limitation, a lot of time/energy was put into tuning StatsAgg's performance. For *most* implementations, a single StatsAgg server should be adequate.
112113
* A few StatsD features that are in the main StatsD program are missing in StatsAgg. Missing features include...
113-
* histograms on timers (will be included in a future build).
114114
* configuring StatsAgg to be a 'repeater' (you can use the official StatsD program to do this, and forward to StatsAgg).
115115
* configuring StatsAgg to be in a 'proxy cluster' configuration (you can use the official StatsD program to do this, and forward to StatsAgg).
116116
* outputting frequently sent metric-keys to log files.

src/main/java/com/pearson/statsagg/database/alert_suspensions/AlertSuspension.java

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,18 @@ public static boolean isValid_SuspensionType(AlertSuspension alertSuspension) {
241241
if (alertSuspension.isRecurThursday() == null) return false;
242242
if (alertSuspension.isRecurFriday() == null) return false;
243243
if (alertSuspension.isRecurSaturday() == null) return false;
244+
245+
// can't suspend for more than 24hrs if alert is recurring
246+
if (alertSuspension.getDuration() > 1440) return false;
247+
if (alertSuspension.getDuration() <= 0) return false;
244248
}
245249

246250
// start dates/times can't be null
247251
if (alertSuspension.getStartDate() == null) return false;
248252
if (alertSuspension.getStartTime() == null) return false;
249253
if (alertSuspension.getDuration() == null) return false;
250-
251-
// can't suspend for more than 24hrs
252-
if (alertSuspension.getDuration() > 1440) return false;
253-
if (alertSuspension.getDuration() <= 0) return false;
254-
255-
// a one-time alert have a 'delete at' date that is in the past
254+
255+
// a one-time alert can't have a 'delete at' date that is in the past
256256
if (alertSuspension.isOneTime() && alertSuspension.getDeleteAtTimestamp() == null) return false;
257257
else if (alertSuspension.isOneTime() && alertSuspension.getDeleteAtTimestamp() != null) {
258258
if (System.currentTimeMillis() >= alertSuspension.getDeleteAtTimestamp().getTime()) {
@@ -297,30 +297,67 @@ public static boolean isAlertSuspensionInSuspensionTimeWindow(AlertSuspension al
297297
return isDateAndTimeInSuspensionWindow;
298298
}
299299

300+
// specifiedDateAndTime will usually refer to 'current date/time'
300301
public static boolean isDateAndTimeInSuspensionWindow(AlertSuspension alertSuspension, Calendar specifiedDateAndTime) {
301302

302-
/* Note -- this method may seem to have a contrived implementation, but the majority of the coding choices for this method were made to
303-
achieve maximum performance. A cleaner, Calendar-only, model was originally used, but it performed 2x slower, so it was replaced with this structure. */
304-
305303
if ((alertSuspension == null) || (alertSuspension.getStartTime() == null) || (alertSuspension.getStartDate() == null) ||
306304
(alertSuspension.getDuration() == null) || (specifiedDateAndTime == null)) {
307305
return false;
308306
}
309307

310308
long alertSuspensionDuration_Milliseconds = 60000 * (long) alertSuspension.getDuration();
311-
long specifiedDateAndTime_Milliseconds = specifiedDateAndTime.getTimeInMillis();
312309
int suspensionStartTime_HourOfDay = alertSuspension.getStartTime().getHours();
313310
int suspensionStartTime_Minute = alertSuspension.getStartTime().getMinutes();
314311
int suspensionStartTime_Second = alertSuspension.getStartTime().getSeconds();
315312
int suspensionStartTime_Millisecond = (int) (alertSuspension.getStartTime().getTime() % 1000);
316-
317-
Date specifiedDateAndTime_Date = new Date(specifiedDateAndTime_Milliseconds);
318-
Date specifiedDateAndTime_MinusDuration = new Date(specifiedDateAndTime_Milliseconds - alertSuspensionDuration_Milliseconds);
319313

320314
// gets a calendar with alertSuspension's date & time. used for checking if specifiedDateAndTime is before the start date/time.
321315
Calendar suspensionStartDateAndTime = DateAndTime.getCalendarWithSameDateAtDifferentTime(alertSuspension.getStartDate(), suspensionStartTime_HourOfDay,
322316
suspensionStartTime_Minute, suspensionStartTime_Second, suspensionStartTime_Millisecond);
323-
317+
318+
if (alertSuspension.isOneTime()) { // handles the 'one time' use-case
319+
return isDateAndTimeInSuspensionWindow_OneTime(alertSuspension, suspensionStartDateAndTime, specifiedDateAndTime, alertSuspensionDuration_Milliseconds);
320+
}
321+
else { // handles the 'recurring' use-case
322+
return isDateAndTimeInSuspensionWindow_Recurring(alertSuspension, suspensionStartDateAndTime, specifiedDateAndTime, alertSuspensionDuration_Milliseconds);
323+
}
324+
}
325+
326+
private static boolean isDateAndTimeInSuspensionWindow_OneTime(AlertSuspension alertSuspension, Calendar suspensionStartDateAndTime,
327+
Calendar specifiedDateAndTime, long alertSuspensionDuration_Milliseconds) {
328+
329+
if ((alertSuspension == null) || (alertSuspension.getStartTime() == null) || (alertSuspension.getStartDate() == null) ||
330+
(alertSuspension.getDuration() == null) || (specifiedDateAndTime == null)) {
331+
return false;
332+
}
333+
334+
long suspensionStartDateAndTime_Milliseconds = suspensionStartDateAndTime.getTimeInMillis();
335+
long specifiedDateAndTime_Milliseconds = specifiedDateAndTime.getTimeInMillis();
336+
long suspensionStartDateAndTime_PlusDuration_Milliseconds = alertSuspensionDuration_Milliseconds + suspensionStartDateAndTime_Milliseconds;
337+
338+
if ((specifiedDateAndTime_Milliseconds >= suspensionStartDateAndTime_Milliseconds) &&
339+
(specifiedDateAndTime_Milliseconds < suspensionStartDateAndTime_PlusDuration_Milliseconds)) {
340+
return true;
341+
}
342+
343+
return false;
344+
}
345+
346+
private static boolean isDateAndTimeInSuspensionWindow_Recurring(AlertSuspension alertSuspension, Calendar suspensionStartDateAndTime,
347+
Calendar specifiedDateAndTime, long alertSuspensionDuration_Milliseconds) {
348+
349+
/* Note -- this method may seem to have a contrived implementation, but the majority of the coding choices for this method were made to
350+
achieve maximum performance. A cleaner, Calendar-only, model was originally used, but it performed 2x slower, so it was replaced with this structure. */
351+
352+
if ((alertSuspension == null) || (alertSuspension.getStartTime() == null) || (alertSuspension.getStartDate() == null) ||
353+
(alertSuspension.getDuration() == null) || (specifiedDateAndTime == null)) {
354+
return false;
355+
}
356+
357+
long specifiedDateAndTime_Milliseconds = specifiedDateAndTime.getTimeInMillis();
358+
Date specifiedDateAndTime_Date = new Date(specifiedDateAndTime_Milliseconds);
359+
Date specifiedDateAndTime_MinusDuration = new Date(specifiedDateAndTime_Milliseconds - alertSuspensionDuration_Milliseconds);
360+
324361
/* covers the cicumstance of specifiedDateAndTime being in an active alert suspension time window, and the time window started the day before specifiedDateAndTime */
325362
if (specifiedDateAndTime_Date.getDate() != specifiedDateAndTime_MinusDuration.getDate()) {
326363
// gets a calendar with a date of "one day before specifiedDateAndTime's date" & alertSuspension's start-time
@@ -349,8 +386,8 @@ public static boolean isDateAndTimeInSuspensionWindow(AlertSuspension alertSuspe
349386
/* covers the cicumstance of dealing with an alert suspension that doesn't involve an alert suspension time window that started the day before specifiedDateAndTime */
350387

351388
// gets a calendar with specifiedDateAndTime's date & alertSuspension's start-time
352-
Calendar startTime_SpecifiedDay = DateAndTime.getCalendarWithSameDateAtDifferentTime((Calendar) specifiedDateAndTime.clone(), suspensionStartTime_HourOfDay,
353-
suspensionStartTime_Minute, suspensionStartTime_Second, suspensionStartTime_Millisecond);
389+
Calendar startTime_SpecifiedDay = DateAndTime.getCalendarWithSameDateAtDifferentTime((Calendar) specifiedDateAndTime.clone(), suspensionStartDateAndTime.get(Calendar.HOUR_OF_DAY),
390+
suspensionStartDateAndTime.get(Calendar.MINUTE), suspensionStartDateAndTime.get(Calendar.SECOND), suspensionStartDateAndTime.get(Calendar.MILLISECOND));
354391
long startTime_SpecifiedDay_Milliseconds = startTime_SpecifiedDay.getTimeInMillis();
355392

356393
// specifiedDateAndTime's start date & time is before alertSuspension's start date & time
@@ -368,7 +405,7 @@ public static boolean isDateAndTimeInSuspensionWindow(AlertSuspension alertSuspe
368405
else {
369406
return false;
370407
}
371-
408+
372409
}
373410

374411
public static boolean isAlertSuspensionAllowed_DayOfWeek(AlertSuspension alertSuspension, Calendar specifiedDateAndTime) {

src/main/java/com/pearson/statsagg/webui/CreateAlertSuspension.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,9 @@ private AlertSuspension getAlertSuspensionFromRequestParameters(HttpServletReque
575575
}
576576

577577
parameter = request.getParameter("Duration");
578-
if ((parameter != null) && !parameter.isEmpty()) {
579-
Integer intValue = Integer.parseInt(parameter.trim());
578+
if (parameter != null) {
579+
String durationStringTrimmed = parameter.trim();
580+
Integer intValue = Integer.parseInt(durationStringTrimmed);
580581
alertSuspension.setDuration(intValue);
581582
}
582583

src/main/webapp/css/jquery.dataTables.css

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,34 @@ table.dataTable tfoot td {
3232
padding: 10px 18px 6px 18px;
3333
border-top: 1px solid #111111;
3434
}
35+
table.dataTable thead .sorting,
3536
table.dataTable thead .sorting_asc,
36-
table.dataTable thead .sorting_desc,
37-
table.dataTable thead .sorting {
37+
table.dataTable thead .sorting_desc {
3838
cursor: pointer;
3939
*cursor: hand;
4040
}
41+
table.dataTable thead .sorting,
42+
table.dataTable thead .sorting_asc,
43+
table.dataTable thead .sorting_desc,
44+
table.dataTable thead .sorting_asc_disabled,
45+
table.dataTable thead .sorting_desc_disabled {
46+
background-repeat: no-repeat;
47+
background-position: center right;
48+
}
4149
table.dataTable thead .sorting {
42-
background: url("../images/sort_both.png") no-repeat center right;
50+
background-image: url("../images/sort_both.png");
4351
}
4452
table.dataTable thead .sorting_asc {
45-
background: url("../images/sort_asc.png") no-repeat center right;
53+
background-image: url("../images/sort_asc.png");
4654
}
4755
table.dataTable thead .sorting_desc {
48-
background: url("../images/sort_desc.png") no-repeat center right;
56+
background-image: url("../images/sort_desc.png");
4957
}
5058
table.dataTable thead .sorting_asc_disabled {
51-
background: url("../images/sort_asc_disabled.png") no-repeat center right;
59+
background-image: url("../images/sort_asc_disabled.png");
5260
}
5361
table.dataTable thead .sorting_desc_disabled {
54-
background: url("../images/sort_desc_disabled.png") no-repeat center right;
62+
background-image: url("../images/sort_desc_disabled.png");
5563
}
5664
table.dataTable tbody tr {
5765
background-color: white;
@@ -203,15 +211,15 @@ table.dataTable.nowrap th, table.dataTable.nowrap td {
203211
}
204212
table.dataTable.compact thead th,
205213
table.dataTable.compact thead td {
206-
padding: 5px 9px;
214+
padding: 4px 17px 4px 4px;
207215
}
208216
table.dataTable.compact tfoot th,
209217
table.dataTable.compact tfoot td {
210-
padding: 5px 9px 3px 9px;
218+
padding: 4px;
211219
}
212220
table.dataTable.compact tbody th,
213221
table.dataTable.compact tbody td {
214-
padding: 4px 5px;
222+
padding: 4px;
215223
}
216224
table.dataTable th.dt-left,
217225
table.dataTable td.dt-left {
@@ -393,6 +401,9 @@ table.dataTable td {
393401
/* W3C */
394402
box-shadow: inset 0 0 3px #111;
395403
}
404+
.dataTables_wrapper .dataTables_paginate .ellipsis {
405+
padding: 0 1em;
406+
}
396407
.dataTables_wrapper .dataTables_processing {
397408
position: absolute;
398409
top: 50%;

0 commit comments

Comments
 (0)