summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-12-20 16:52:47 +0100
committerRoland Reichwein <mail@reichwein.it>2020-12-20 16:52:47 +0100
commit73f0b597dec0705db01ed4eec7abaebc0295a243 (patch)
tree3599be15154a9eeaa09cb86e1918a13ac3a73bef
parentef63da27938ae091a341893c38e59d489888625a (diff)
webserver 1.12: Added graphical statistics page (gnuplot generated)
-rw-r--r--debian/changelog7
-rw-r--r--debian/control2
-rw-r--r--libcommon/tempfile.cpp14
-rw-r--r--libcommon/tempfile.h3
-rw-r--r--plugins/statistics/Makefile4
-rw-r--r--plugins/statistics/statistics.cpp48
-rw-r--r--plugins/webbox/webbox.cpp3
-rw-r--r--plugins/weblog/weblog.cpp2
8 files changed, 71 insertions, 12 deletions
diff --git a/debian/changelog b/debian/changelog
index 954078d..8075e41 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+webserver (1.12) unstable; urgency=medium
+
+ * Add gnuplot generated statistics in statistics plugin
+ * End articles with square
+
+ -- Roland Reichwein <rr@antcom.de> Sat, 19 Dec 2020 11:36:46 +0100
+
webserver (1.11) unstable; urgency=medium
* Bugfix: ZIP download in webbox was broken
diff --git a/debian/control b/debian/control
index 5ea967d..9738e34 100644
--- a/debian/control
+++ b/debian/control
@@ -8,7 +8,7 @@ Homepage: http://www.reichwein.it/webserver/
Package: webserver
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, zip
+Depends: ${shlibs:Depends}, ${misc:Depends}, zip, gnuplot
Provides: httpd
Homepage: http://www.reichwein.it/webserver/
Description: Web server
diff --git a/libcommon/tempfile.cpp b/libcommon/tempfile.cpp
index c30bb57..f425db2 100644
--- a/libcommon/tempfile.cpp
+++ b/libcommon/tempfile.cpp
@@ -14,10 +14,15 @@ fs::path Tempfile::GetPath() const
return m_path;
}
-Tempfile::Tempfile() {
+Tempfile::Tempfile(const std::filesystem::path& extension)
+{
try {
- char name[] = "/tmp/tempfileXXXXXX.zip";
- int fd = mkstemps(name, 4);
+ fs::path path { fs::temp_directory_path() / "tempfileXXXXXX"};
+ if (!extension.empty())
+ path += extension;
+
+ fs::path::string_type name{path.native()};
+ int fd = mkstemps(name.data(), extension.native().size());
if (fd == -1)
std::runtime_error("mkstemps: "s + strerror(errno));
close(fd);
@@ -27,7 +32,8 @@ Tempfile::Tempfile() {
}
}
-Tempfile::~Tempfile() {
+Tempfile::~Tempfile()
+{
try {
fs::remove_all(m_path);
} catch (const std::exception& ex) {
diff --git a/libcommon/tempfile.h b/libcommon/tempfile.h
index 5938fb9..b9839a7 100644
--- a/libcommon/tempfile.h
+++ b/libcommon/tempfile.h
@@ -9,7 +9,8 @@ class Tempfile
public:
std::filesystem::path GetPath() const;
- Tempfile();
+ // extension: e.g. ".zip"
+ Tempfile(const std::filesystem::path& extension = std::filesystem::path{});
~Tempfile();
};
diff --git a/plugins/statistics/Makefile b/plugins/statistics/Makefile
index 8e8a6f7..34c0229 100644
--- a/plugins/statistics/Makefile
+++ b/plugins/statistics/Makefile
@@ -28,8 +28,8 @@ SRC=$(PROGSRC)
all: $(PROJECTNAME).so
-$(PROJECTNAME).so: $(SRC:.cpp=.o)
- $(CXX) $(CXXFLAGS) $^ -shared $(LIBS) -o $@
+$(PROJECTNAME).so: ../../libcommon/libcommon.a $(SRC:.cpp=.o)
+ $(CXX) $(LDFLAGS) $^ -shared $(LDLIBS) $(LIBS) -o $@
../../libcommon/libcommon.a:
cd ../.. && $(MAKE) libcommon/libcommon.a
diff --git a/plugins/statistics/statistics.cpp b/plugins/statistics/statistics.cpp
index b1778f7..415369d 100644
--- a/plugins/statistics/statistics.cpp
+++ b/plugins/statistics/statistics.cpp
@@ -1,5 +1,8 @@
#include "statistics.h"
+#include "libcommon/file.h"
+#include "libcommon/tempfile.h"
+
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/coroutine2/coroutine.hpp>
@@ -23,9 +26,48 @@ namespace {
{
SetResponseHeader("status", status);
SetResponseHeader("content_type", "text/html");
+
return status + " " + message;
}
+ std::string statsPng(std::function<std::string(const std::string& key)>& GetServerParam,
+ std::function<plugin_interface_setter_type>& SetResponseHeader)
+ {
+ // Create PNG statistics via Gnuplot
+ std::string statistics{GetServerParam("statistics")};
+
+ Tempfile tempStats{".txt"}; // input data
+ File::setFile(tempStats.GetPath(), statistics);
+
+ Tempfile tempPng{".png"}; // output
+
+ Tempfile tempGnuplot{".gnuplot"};
+ std::stringstream s;
+ s << "set terminal png truecolor\n";
+ s << "set output " << tempPng.GetPath() << "\n"; // quotes added automatically for paths
+ s << "set title \"Webserver Throughput\"\n";
+ s << "set xlabel \"Time\"\n";
+ s << "set timefmt \"%s\"\n";
+ s << "set format x \"%Y-%m-%d\"\n";
+ s << "set xdata time\n";
+ s << "set xtics rotate by 45 right\n";
+ s << "set ylabel \"Bytes\"\n";
+ s << "set datafile separator \",\"\n";
+ s << "set grid\n";
+ s << "set style fill solid\n";
+ s << "plot " << tempStats.GetPath() << " using 1:($4+$5) with boxes title \"Bytes I/O\" lt rgb \"#1132A7\"\n";
+ File::setFile(tempGnuplot.GetPath(), s.str());
+
+ int exit_code{system(("gnuplot "s + tempGnuplot.GetPath().generic_string()).c_str())};
+ if (exit_code) {
+ std::cerr << "Error: gnuplot returned " << std::to_string(exit_code) << std::endl;
+ return HttpStatus("500", "Statistics error"s, SetResponseHeader);
+ }
+
+ SetResponseHeader("content_type", "image/png");
+ return File::getFile(tempPng.GetPath());
+ }
+
// returns sum over specified column
uint64_t getSum(const std::string& stats, size_t column)
{
@@ -95,9 +137,12 @@ std::string statistics_plugin::generate_page(
if (target.size() && target.back() != '/' && fs::is_directory(path)) {
std::string location{GetRequestParam("location") + "/"s};
SetResponseHeader("location", location);
- return HttpStatus("301", "Correcting directory path", SetResponseHeader);
+ return HttpStatus("301", "Correcting directory path", SetResponseHeader); // 301 Moved Permanently
}
+ if (path.filename() == "stats.png")
+ return statsPng(GetServerParam, SetResponseHeader);
+
try {
SetResponseHeader("content_type", "text/html");
@@ -122,6 +167,7 @@ std::string statistics_plugin::generate_page(
result += "<p>IPv6 fraction by bytes: "s + std::to_string(ipv6_fraction_by_bytes * 100) + "%</p>";
result += "<p>HTTPS fraction by requests: "s + std::to_string(https_fraction_by_requests * 100) + "%</p>";
result += "<p>HTTPS fraction by bytes: "s + std::to_string(https_fraction_by_bytes * 100) + "%</p>";
+ result += "<p><img src=\"stats.png\"/></p>";
result += "<pre>"s + statistics + "</pre>"s;
result += footer;
diff --git a/plugins/webbox/webbox.cpp b/plugins/webbox/webbox.cpp
index d19f428..26d49c8 100644
--- a/plugins/webbox/webbox.cpp
+++ b/plugins/webbox/webbox.cpp
@@ -5,7 +5,6 @@
#include "libcommon/file.h"
#include "libcommon/stringutil.h"
-
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -511,7 +510,7 @@ protected:
return HttpStatus("500", "Change path error: "s + ex.what(), p);
}
- Tempfile tempfile; // guards this path, removing file afterwards via RAII
+ Tempfile tempfile{".zip"}; // guards this path, removing file afterwards via RAII
arglist = "/usr/bin/zip -r - "s + arglist + " > "s + tempfile.GetPath().string();
diff --git a/plugins/weblog/weblog.cpp b/plugins/weblog/weblog.cpp
index a64ee1b..c26a4fe 100644
--- a/plugins/weblog/weblog.cpp
+++ b/plugins/weblog/weblog.cpp
@@ -302,7 +302,7 @@ namespace {
HtmlPage htmlPage{GetRequestParam, "<h1>"s + metaData.at("Subject") + "</h1>"
"<div class=\"date\">" + metaData.at("Date") + "</div>"
- "<br/><br/>"s + data};
+ "<br/><br/>"s + data + "<br/>&squ;"};
return htmlPage;
} catch (const std::exception& ex) {