diff --git a/NASA_IMAGES.txt b/NASA_IMAGES.txt
new file mode 100644
index 000000000..c19087e58
--- /dev/null
+++ b/NASA_IMAGES.txt
@@ -0,0 +1,7 @@
+The images used as login screen backgrounds are from the Nasa Commons and do not fall under any copyright restrictions.
+
+ * http://www.flickr.com/photos/nasacommons/4858567220
+
+Fore more information see http://www.nasa.gov/audience/formedia/features/MP_Photo_Guidelines.html
+
+Thank you, NASA.
\ No newline at end of file
diff --git a/app/controllers/MessageCountsController.java b/app/controllers/MessageCountsController.java
index 1b75b29ca..4bbcfe47f 100644
--- a/app/controllers/MessageCountsController.java
+++ b/app/controllers/MessageCountsController.java
@@ -9,13 +9,31 @@
import com.google.gson.Gson;
import lib.APIException;
-import models.MessageCount;
+import models.MessageCountHistogram;
import models.api.results.DateHistogramResult;
+import models.MessageCount;
+import models.api.results.MessageCountResult;
import play.mvc.*;
public class MessageCountsController extends AuthenticatedController {
- public static Result total(String timerange) {
+ public static Result total() {
+ try {
+ MessageCount count = new MessageCount();
+ MessageCountResult countResult = count.total();
+
+ Map result = Maps.newHashMap();
+ result.put("events", countResult.getEventsCount());
+
+ return ok(new Gson().toJson(result)).as("application/json");
+ } catch (IOException e) {
+ return internalServerError("io exception");
+ } catch (APIException e) {
+ return internalServerError("api exception " + e);
+ }
+ }
+
+ public static Result histogram(String timerange) {
int range;
try {
range = Integer.parseInt(timerange);
@@ -24,8 +42,8 @@ public static Result total(String timerange) {
}
try {
- MessageCount count = new MessageCount("minute", range);
- DateHistogramResult histogramResult = count.total();
+ MessageCountHistogram count = new MessageCountHistogram("minute", range);
+ DateHistogramResult histogramResult = count.histogram();
List> lines = Lists.newArrayList();
Map r = Maps.newTreeMap();
@@ -37,9 +55,9 @@ public static Result total(String timerange) {
return ok(new Gson().toJson(lines)).as("application/json");
} catch (IOException e) {
- return ok("io exception");
+ return internalServerError("io exception");
} catch (APIException e) {
- return ok("api exception" + e);
+ return internalServerError("api exception " + e);
}
}
diff --git a/app/controllers/SearchController.java b/app/controllers/SearchController.java
index 72c8c0a3b..136577b95 100755
--- a/app/controllers/SearchController.java
+++ b/app/controllers/SearchController.java
@@ -35,7 +35,11 @@ public static Result index(String q, String timerange, String interval) {
SearchResult searchResult = search.search();
DateHistogramResult histogramResult = search.dateHistogram(interval);
- return ok(views.html.search.results.render(currentUser(), searchResult, histogramResult, q));
+ if (searchResult.getTotalResultCount() > 0) {
+ return ok(views.html.search.results.render(currentUser(), searchResult, histogramResult, q));
+ } else {
+ return ok(views.html.search.noresults.render(currentUser(), q));
+ }
} catch (IOException e) {
return status(504, views.html.errors.error.render(Api.ERROR_MSG_IO, e, request()));
} catch (APIException e) {
diff --git a/app/controllers/SessionsController.java b/app/controllers/SessionsController.java
index 5b59c6faa..aa1a34628 100644
--- a/app/controllers/SessionsController.java
+++ b/app/controllers/SessionsController.java
@@ -12,6 +12,11 @@ public class SessionsController extends Controller {
final static Form userForm = form(LoginRequest.class);
public static Result index() {
+ // Redirect if already logged in.
+ if (session("username") != null && !session("username").isEmpty()) {
+ return redirect("/");
+ }
+
return ok(views.html.sessions.login.render(userForm));
}
diff --git a/app/lib/Tools.java b/app/lib/Tools.java
new file mode 100644
index 000000000..4f122f42b
--- /dev/null
+++ b/app/lib/Tools.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2013 Lennart Koopmann
+ *
+ * This file is part of Graylog2.
+ *
+ * Graylog2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Graylog2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Graylog2. If not, see .
+ *
+ */
+package lib;
+
+import java.util.Random;
+
+/**
+ * @author Lennart Koopmann
+ */
+public class Tools {
+
+ private Tools() { /* pure utility class */ }
+
+ public static int random(int min, int max) {
+ Random rand = new Random();
+ return rand.nextInt(max - min + 1) + min;
+ }
+
+}
diff --git a/app/models/MessageCount.java b/app/models/MessageCount.java
index 3403cea05..3265ab8db 100644
--- a/app/models/MessageCount.java
+++ b/app/models/MessageCount.java
@@ -1,29 +1,29 @@
package models;
-import java.io.IOException;
-import java.net.URL;
-
import lib.APIException;
import lib.Api;
-import models.api.responses.DateHistogramResponse;
-import models.api.results.DateHistogramResult;
+import models.api.responses.MessageCountResponse;
+import models.api.results.MessageCountResult;
+import play.cache.Cache;
+
+import java.io.IOException;
+import java.net.URL;
public class MessageCount {
- private final String interval;
- private final int timerange;
-
- public MessageCount(String interval, int timerange) {
- this.interval = interval;
- this.timerange = timerange;
- }
-
- public DateHistogramResult total() throws IOException, APIException {
- String i = Api.urlEncode(interval);
- URL url = Api.buildTarget("count/total?interval=" + i + "&timerange=" + timerange);
-
- DateHistogramResponse response = Api.get(url, new DateHistogramResponse());
- return new DateHistogramResult("match_all", response.time, response.interval, response.results);
- }
-
+ public static final int TOTAL_CNT_CACHE_TTL = 2; // seconds
+ public static final String TOTAL_CNT_CACHE_KEY = "counts.total";
+
+ public MessageCountResult total() throws IOException, APIException {
+ MessageCountResult cached = (MessageCountResult) Cache.get(TOTAL_CNT_CACHE_KEY);
+ if (cached != null) {
+ return cached;
+ }
+
+ MessageCountResponse response = Api.get(Api.buildTarget("count/total"), new MessageCountResponse());
+ MessageCountResult result = new MessageCountResult(response.events);
+ Cache.set(TOTAL_CNT_CACHE_KEY, result, TOTAL_CNT_CACHE_TTL);
+ return result;
+ }
+
}
diff --git a/app/models/MessageCountHistogram.java b/app/models/MessageCountHistogram.java
new file mode 100644
index 000000000..18b5dd58e
--- /dev/null
+++ b/app/models/MessageCountHistogram.java
@@ -0,0 +1,29 @@
+package models;
+
+import java.io.IOException;
+import java.net.URL;
+
+import lib.APIException;
+import lib.Api;
+import models.api.responses.DateHistogramResponse;
+import models.api.results.DateHistogramResult;
+
+public class MessageCountHistogram {
+
+ private final String interval;
+ private final int timerange;
+
+ public MessageCountHistogram(String interval, int timerange) {
+ this.interval = interval;
+ this.timerange = timerange;
+ }
+
+ public DateHistogramResult histogram() throws IOException, APIException {
+ String i = Api.urlEncode(interval);
+ URL url = Api.buildTarget("count/histogram?interval=" + i + "&timerange=" + timerange);
+
+ DateHistogramResponse response = Api.get(url, new DateHistogramResponse());
+ return new DateHistogramResult("match_all", response.time, response.interval, response.results);
+ }
+
+}
diff --git a/app/models/api/responses/MessageCountResponse.java b/app/models/api/responses/MessageCountResponse.java
new file mode 100644
index 000000000..3aee9d096
--- /dev/null
+++ b/app/models/api/responses/MessageCountResponse.java
@@ -0,0 +1,7 @@
+package models.api.responses;
+
+public class MessageCountResponse {
+
+ public int events;
+
+}
diff --git a/app/models/api/results/MessageCountResult.java b/app/models/api/results/MessageCountResult.java
new file mode 100644
index 000000000..189d85892
--- /dev/null
+++ b/app/models/api/results/MessageCountResult.java
@@ -0,0 +1,15 @@
+package models.api.results;
+
+public class MessageCountResult {
+
+ private final int eventsCount;
+
+ public MessageCountResult(int eventsCount) {
+ this.eventsCount = eventsCount;
+ }
+
+ public int getEventsCount() {
+ return eventsCount;
+ }
+
+}
diff --git a/app/models/api/results/SearchResult.java b/app/models/api/results/SearchResult.java
index 4e32f0ac0..ac2c00523 100644
--- a/app/models/api/results/SearchResult.java
+++ b/app/models/api/results/SearchResult.java
@@ -45,10 +45,12 @@ public List getFields() {
private List buildFields(List sFields) {
List fields = Lists.newArrayList();
-
- for (String field : sFields) {
- fields.add(new Field(field));
- }
+
+ if (sFields != null) {
+ for (String field : sFields) {
+ fields.add(new Field(field));
+ }
+ }
return fields;
}
diff --git a/app/views/auth.scala.html b/app/views/auth.scala.html
index ceededa94..d5ba623e3 100644
--- a/app/views/auth.scala.html
+++ b/app/views/auth.scala.html
@@ -8,11 +8,14 @@
+
+
+
@content
diff --git a/app/views/dashboard/index.scala.html b/app/views/dashboard/index.scala.html
index 4a66a301c..7929b01fa 100755
--- a/app/views/dashboard/index.scala.html
+++ b/app/views/dashboard/index.scala.html
@@ -2,4 +2,6 @@
@main("Dashboard", sidebars.standard(currentUser), "", currentUser) {
+ Containing [ ] events.
+
}
\ No newline at end of file
diff --git a/app/views/errors/error.scala.html b/app/views/errors/error.scala.html
index 2a02ca6a5..316ba8f4b 100644
--- a/app/views/errors/error.scala.html
+++ b/app/views/errors/error.scala.html
@@ -15,13 +15,7 @@
Reason: @message
-What should I do now?
-
- Please consult the support pages if you don't
- know how to fix this problem. Contact the
- mailing list or file an issue if in
- doubt about anything or you have questions left.
-
+@partials.support_sources()
Stacktrace
diff --git a/app/views/partials/support_sources.scala.html b/app/views/partials/support_sources.scala.html
new file mode 100644
index 000000000..96a5dffd8
--- /dev/null
+++ b/app/views/partials/support_sources.scala.html
@@ -0,0 +1,11 @@
+
+
Need help?
+ Do not hesitate to consult the Graylog2 community if your questions are not answered in the
+
documentation .
+
+
+
\ No newline at end of file
diff --git a/app/views/search/noresults.scala.html b/app/views/search/noresults.scala.html
new file mode 100644
index 000000000..2a5c5c88c
--- /dev/null
+++ b/app/views/search/noresults.scala.html
@@ -0,0 +1,16 @@
+@(currentUser: User, query: String)
+
+@main("Search results", sidebars.standard(currentUser), query, currentUser) {
+
+
+ Nothing found
+
+
+
+ Your search returned no results. Take a look at the
+ documentation
+ if you need help with the search syntax.
+
+
+ @partials.support_sources()
+}
\ No newline at end of file
diff --git a/app/views/sessions/login.scala.html b/app/views/sessions/login.scala.html
index 5799cc860..4abca3ed2 100644
--- a/app/views/sessions/login.scala.html
+++ b/app/views/sessions/login.scala.html
@@ -1,28 +1,26 @@
@(loginForm: Form[LoginRequest])
-@auth(title = "Login") {
+@auth(title = "Welcome to Graylog2 - Sign in") {
-
+
-
-
Welcome to Graylog2
-
+
diff --git a/app/views/sidebars/searchresults.scala.html b/app/views/sidebars/searchresults.scala.html
index b9ec12f94..ae6903188 100644
--- a/app/views/sidebars/searchresults.scala.html
+++ b/app/views/sidebars/searchresults.scala.html
@@ -9,6 +9,7 @@
Found @searchResult.getTotalResultCount() messages in @searchResult.getTookMs()ms.
+@if(searchResult.getTotalResultCount() > 0) {
Select fields
@for(f <- searchResult.getFields()) {
@@ -27,4 +28,5 @@ Select fields
Analyze field
-... tba ...
\ No newline at end of file
+... tba ...
+}
\ No newline at end of file
diff --git a/conf/routes b/conf/routes
index bdaa6c4d3..319e965af 100755
--- a/conf/routes
+++ b/conf/routes
@@ -19,8 +19,9 @@ GET /messages/:index/:id/partial controllers.MessagesController.asPartial(index
# Streams
GET /streams controllers.StreamsController.index()
-# API: Message counts
-GET /a/messagecounts/total controllers.MessageCountsController.total(timerange ?= "")
+# API: Message counts and histograms
+GET /a/messagecounts/histogram controllers.MessageCountsController.histogram(timerange ?= "")
+GET /a/messagecounts/total controllers.MessageCountsController.total()
# API: Message analyzing
GET /a/analyze/:index/:id/:field controllers.MessagesController.analyze(index: String, id: String, field: String)
diff --git a/public/images/auth/loginbg.jpg b/public/images/auth/loginbg.jpg
new file mode 100644
index 000000000..fb7b25a80
Binary files /dev/null and b/public/images/auth/loginbg.jpg differ
diff --git a/public/images/auth/pattern.png b/public/images/auth/pattern.png
deleted file mode 100644
index 47ab3a4a4..000000000
Binary files a/public/images/auth/pattern.png and /dev/null differ
diff --git a/public/javascripts/graphs.js b/public/javascripts/graphs.js
index 5927f02b8..11b9d7b81 100644
--- a/public/javascripts/graphs.js
+++ b/public/javascripts/graphs.js
@@ -1,6 +1,6 @@
$(document).ready(function() {
- // Sidebar graph. (total message counts)
+ // Sidebar graph. (histogram message counts)
if (document.querySelector("#sidebar-graph") != null) {
var sidebarGraph = new Rickshaw.Graph.Ajax({
element: document.querySelector("#sidebar-graph"),
@@ -9,7 +9,7 @@ $(document).ready(function() {
renderer: 'bar',
interpolation: 'linear',
stroke: true,
- dataURL: '/a/messagecounts/total?timerange=' + 2*60*60, // last two hours
+ dataURL: '/a/messagecounts/histogram?timerange=' + 2*60*60, // last two hours
onData: function(d) { return transformData(d) },
onError: function(d) {
error = " Could not load graph ";
diff --git a/public/javascripts/main.js b/public/javascripts/main.js
index a4c824414..59ca81bde 100755
--- a/public/javascripts/main.js
+++ b/public/javascripts/main.js
@@ -84,6 +84,24 @@ $(document).ready(function() {
}
});
+ // Updating total event counts;
+
+ (function updateTotalEvents() {
+ $.ajax({
+ url: '/a/messagecounts/total',
+ success: function(data) {
+ $(".total-events").html(data.events);
+ },
+ error: function() {
+ $(".total-events").html("?");
+ },
+ complete: function() {
+ setTimeout(updateTotalEvents, 2500);
+ }
+ });
+ })();
+
+
function displayFailureInSidebar(message) {
x = ""
$("#sidebar-inner").html(x);
diff --git a/public/stylesheets/auth.css b/public/stylesheets/auth.css
index 7c215825f..ab6278992 100644
--- a/public/stylesheets/auth.css
+++ b/public/stylesheets/auth.css
@@ -1,5 +1,26 @@
body {
- background-color: #fff;
- /* background-image: url("/assets/images/auth/pattern.png"); */
- margin-top: 30px;
+ font-family: 'Open Sans', sans-serif;
+
+ /* we love science */
+ background: url('/assets/images/auth/loginbg.jpg') no-repeat center center fixed;
+ -moz-background-size: cover;
+ -webkit-background-size: cover;
+ -o-background-size: cover;
+ background-size: cover;
+}
+
+#login-box {
+ margin-top: 120px;
+}
+
+#login-box-content {
+ background-color: #fff;
+ -moz-box-shadow: 0 0 5px #888;
+ -webkit-box-shadow: 0 0 5px#888;
+ box-shadow: 0 0 40px #000;
+}
+
+.well {
+ padding-top: 8px;
+ padding-bottom: 2px;
}
\ No newline at end of file
diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css
index a4bbb99ca..96dcf2555 100644
--- a/public/stylesheets/main.css
+++ b/public/stylesheets/main.css
@@ -214,4 +214,8 @@ h3 {
.terms-msg-modal .modal-body .as-list li {
float: none !important;
+}
+
+.support-sources ul {
+ margin-top: 5px;
}
\ No newline at end of file