[Libreoffice-commits] online.git: loleaflet/admin.strings.js loleaflet/build loleaflet/dist loleaflet/Makefile.am loleaflet/src wsd/Admin.cpp wsd/AdminModel.cpp wsd/AdminModel.hpp wsd/protocol.txt
Marco Viscido
marcoviscido at gmail.com
Wed Apr 19 02:08:57 UTC 2017
loleaflet/Makefile.am | 1
loleaflet/admin.strings.js | 1
loleaflet/build/adminDeps.js | 6 +
loleaflet/dist/admin/admin.html | 1
loleaflet/dist/admin/adminAnalytics.html | 5 -
loleaflet/dist/admin/adminHistory.html | 85 +++++++++++++++++++++
loleaflet/dist/admin/adminSettings.html | 1
loleaflet/src/admin/AdminSocketHistory.js | 51 +++++++++++++
wsd/Admin.cpp | 4 +
wsd/AdminModel.cpp | 117 +++++++++++++++++++++++++++---
wsd/AdminModel.hpp | 14 ++-
wsd/protocol.txt | 34 ++++++++
12 files changed, 304 insertions(+), 16 deletions(-)
New commits:
commit 0bb650e7c48deb65167305d7d11b61f83ea738b1
Author: Marco Viscido <marcoviscido at gmail.com>
Date: Mon Apr 17 20:36:04 2017 +0200
keep expired document and query them to get the historical content
A Document has its own snapshots set.
A snapshot is a string representation of a JSON object.
AdminModel keeps also the expired document objects.
Query each document object in order to get their own history.
Admin accepts an "history" command then returns a json object.
An administrator checks the history by dashboard.
Change-Id: I73c87eff334cdb5a4a58043b2b66f18a56240b3a
Reviewed-on: https://gerrit.libreoffice.org/35926
Reviewed-by: pranavk <pranavk at collabora.co.uk>
Tested-by: pranavk <pranavk at collabora.co.uk>
diff --git a/loleaflet/Makefile.am b/loleaflet/Makefile.am
index 0a1880ae..a2d4a617 100644
--- a/loleaflet/Makefile.am
+++ b/loleaflet/Makefile.am
@@ -52,6 +52,7 @@ pot:
dist/toolbar/toolbar.js \
src/admin/AdminSocketBase.js \
src/admin/AdminSocketOverview.js \
+ src/admin/AdminSocketHistory.js \
src/admin/AdminSocketSettings.js \
src/admin/Util.js \
src/control/Control.CharacterMap.js \
diff --git a/loleaflet/admin.strings.js b/loleaflet/admin.strings.js
index fcfb574a..e5116276 100644
--- a/loleaflet/admin.strings.js
+++ b/loleaflet/admin.strings.js
@@ -8,6 +8,7 @@ l10nstrings.strSettings = _('Settings');
l10nstrings.strOverview = _('Overview');
l10nstrings.strCurrent = _('(current)');
l10nstrings.strAnalytics = _('Analytics');
+l10nstrings.strHistory = _('History');
l10nstrings.strDashboard = _('Dashboard');
l10nstrings.strUsersOnline = _('Users online');
l10nstrings.strDocumentsOpened = _('Documents opened');
diff --git a/loleaflet/build/adminDeps.js b/loleaflet/build/adminDeps.js
index 5c2dd5da..f6efdad9 100644
--- a/loleaflet/build/adminDeps.js
+++ b/loleaflet/build/adminDeps.js
@@ -28,6 +28,12 @@ var adminDeps = {
src: ['admin/AdminSocketSettings.js'],
desc: 'Socket to handle settings from server',
deps: ['AdminCore']
+ },
+
+ AdminSocketHistory: {
+ src: ['admin/AdminSocketHistory.js'],
+ desc: 'Socket to query document history.',
+ deps: ['AdminCore']
}
};
diff --git a/loleaflet/dist/admin/admin.html b/loleaflet/dist/admin/admin.html
index 0d44ea4e..98a99eb8 100644
--- a/loleaflet/dist/admin/admin.html
+++ b/loleaflet/dist/admin/admin.html
@@ -58,6 +58,7 @@
<ul class="nav nav-sidebar">
<li class="active"><a href="#"><script>document.write(l10nstrings.strOverview)</script> <span class="sr-only"><script>document.write(l10nstrings.strCurrent)</script></span></a></li>
<li><a href="adminAnalytics.html"><script>document.write(l10nstrings.strAnalytics)</script></a></li>
+ <li><a href="adminHistory.html"><script>document.write(l10nstrings.strHistory)</script></a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
diff --git a/loleaflet/dist/admin/adminAnalytics.html b/loleaflet/dist/admin/adminAnalytics.html
index a0f7beef..2d7a37db 100644
--- a/loleaflet/dist/admin/adminAnalytics.html
+++ b/loleaflet/dist/admin/adminAnalytics.html
@@ -56,8 +56,9 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
- <li><a href="admin.html"><script>document.write(l10nstrings.strOverview)</script> <span class="sr-only"><script>document.write(l10nstrings.strCurrent)</script></span></a></li>
- <li class="active"><a href="adminAnalytics.html"><script>document.write(l10nstrings.strAnalytics)</script></a></li>
+ <li><a href="admin.html"><script>document.write(l10nstrings.strOverview)</script></a></li>
+ <li class="active"><a href="adminAnalytics.html"><script>document.write(l10nstrings.strAnalytics)</script> <span class="sr-only"><script>document.write(l10nstrings.strCurrent)</script></span></a></li>
+ <li><a href="adminHistory.html"><script>document.write(l10nstrings.strHistory)</script></a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
diff --git a/loleaflet/dist/admin/adminHistory.html b/loleaflet/dist/admin/adminHistory.html
new file mode 100644
index 00000000..60f53f6a
--- /dev/null
+++ b/loleaflet/dist/admin/adminHistory.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <title>LibreOffice Online - Admin console</title>
+
+ <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
+ <!--[if lt IE 9]>
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+ <![endif]-->
+ <link rel="localizations" href="/loleaflet/dist/l10n/localizations.json" type="application/vnd.oftn.l10n+json"/>
+
+ </head>
+ <body>
+ <script src="/loleaflet/dist/admin-bundle.js"></script>
+ <script src="/loleaflet/dist/branding.js"></script>
+ <script>if (brandProductName) {l10nstrings.strProductName = brandProductName}</script>
+ <script>document.title = l10nstrings.strProductName + ' - ' + l10nstrings.strAdminConsole</script>
+ <script>
+ if (window.location.protocol == "https:") {
+ host = 'wss://' + window.location.host + '/lool/adminws/'
+ }
+ else {
+ host = 'ws://' + window.location.host + '/lool/adminws/'
+ }
+
+ Admin.History(host)
+ </script>
+
+<nav class="navbar navbar-inverse navbar-fixed-top">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+ <span class="sr-only"><script>document.write(l10nstrings.strToggleNavigation)</script></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="#"><script>document.write(l10nstrings.strProductName + ' - ' + l10nstrings.strAdminConsole)</script></a>
+ </div>
+ <div id="navbar" class="navbar-collapse collapse">
+ <ul class="nav navbar-nav navbar-right">
+ <li><a href="adminSettings.html"><script>document.write(l10nstrings.strSettings)</script></a></li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+ <div class="container-fluid">
+ <div class="row">
+ <div class="col-sm-3 col-md-2 sidebar">
+ <ul class="nav nav-sidebar">
+ <li><a href="admin.html"><script>document.write(l10nstrings.strOverview)</script></a></li>
+ <li><a href="adminAnalytics.html"><script>document.write(l10nstrings.strAnalytics)</script></a></li>
+ <li class="active"><a href="adminHistory.html"><script>document.write(l10nstrings.strHistory)</script> <span class="sr-only"><script>document.write(l10nstrings.strCurrent)</script></span></a></li>
+ </ul>
+ </div>
+
+ <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
+ <h1 class="page-header"><script>document.write(l10nstrings.strHistory)</script>
+ <button class="pull-right" id="refreshHistory">refresh</button>
+ </h1>
+ <pre id="json-doc">Documents:<br/><textarea rows="10" cols="100"></textarea></pre>
+ <pre id="json-ex-doc">Expired:<br/><textarea rows="10" cols="100"></textarea></pre>
+ </div>
+ </div>
+ </div>
+
+
+ <!-- Bootstrap core JavaScript
+ ================================================== -->
+ <!-- Placed at the end of the document so the pages load faster -->
+ <script src="../../dist/bootstrap/js/bootstrap.min.js"></script>
+ <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
+ <script src="../../dist/bootstrap/assets/js/vendor/holder.min.js"></script>
+ <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
+ <script src="../../dist/bootstrap/assets/js/ie10-viewport-bug-workaround.js"></script>
+ </body>
+</html>
diff --git a/loleaflet/dist/admin/adminSettings.html b/loleaflet/dist/admin/adminSettings.html
index 3b74b80e..bba47f90 100644
--- a/loleaflet/dist/admin/adminSettings.html
+++ b/loleaflet/dist/admin/adminSettings.html
@@ -58,6 +58,7 @@
<ul class="nav nav-sidebar">
<li><a href="admin.html"><script>document.write(l10nstrings.strOverview)</script> <span class="sr-only"><script>document.write(l10nstrings.strCurrent)</script></span></a></li>
<li><a href="adminAnalytics.html"><script>document.write(l10nstrings.strAnalytics)</script></a></li>
+ <li><a href="adminHistory.html"><script>document.write(l10nstrings.strHistory)</script></a></li>
</ul>
<hr />
<div style="position:absolute; bottom:0px">
diff --git a/loleaflet/src/admin/AdminSocketHistory.js b/loleaflet/src/admin/AdminSocketHistory.js
new file mode 100644
index 00000000..05f9b063
--- /dev/null
+++ b/loleaflet/src/admin/AdminSocketHistory.js
@@ -0,0 +1,51 @@
+/*
+ Socket to be intialized on opening the history page in Admin console
+*/
+/* global $ nodejson2html Util AdminSocketBase */
+/* eslint no-unused-vars:0 */
+var AdminSocketHistory = AdminSocketBase.extend({
+ constructor: function(host) {
+ this.base(host);
+ },
+
+ refreshHistory: function() {
+ this.socket.send('history');
+ },
+
+ onSocketOpen: function() {
+ // Base class' onSocketOpen handles authentication
+ this.base.call(this);
+
+ var socketHistory = this;
+ $('#refreshHistory').on('click', function () {
+ return socketHistory.refreshHistory();
+ });
+ this.refreshHistory();
+ },
+
+ onSocketMessage: function(e) {
+ //if (e.data == 'InvalidAuthToken' || e.data == 'NotAuthenticated') {
+ // this.base.call(this);
+ // this.refreshHistory();
+ //} else {
+ var jsonObj;
+ try {
+ jsonObj = JSON.parse(e.data);
+ var doc = jsonObj['History']['documents'];
+ var exdoc = jsonObj['History']['expiredDocuments'];
+ $('#json-doc').find('textarea').html(JSON.stringify(doc));
+ $('#json-ex-doc').find('textarea').html(JSON.stringify(exdoc));
+ } catch (e) {
+ $('document').alert(e.message);
+ }
+ },
+
+ onSocketClose: function() {
+
+ }
+});
+
+Admin.History = function(host) {
+ return new AdminSocketHistory(host);
+};
+
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index a9039f2b..f5b63b1e 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -108,6 +108,10 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */,
if (!result.empty())
sendTextFrame(tokens[0] + ' ' + result);
}
+ else if (tokens[0] == "history")
+ {
+ sendTextFrame("{ \"History\": " + model.getAllHistory() + "}");
+ }
else if (tokens[0] == "version")
{
// Send LOOL version information
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index a838cbf3..3429553f 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -50,10 +50,80 @@ int Document::expireView(const std::string& sessionId)
if (--_activeViews == 0)
_end = std::time(nullptr);
}
+ this->takeSnapshot();
return _activeViews;
}
+std::pair<std::time_t, std::string> Document::getSnapshot() const
+{
+ std::time_t ct = std::time(nullptr);
+ std::ostringstream oss;
+ oss << "{";
+ oss << "\"creationTime\"" << ":" << ct << ",";
+ oss << "\"memoryDirty\"" << ":" << this->getMemoryDirty() << ",";
+ oss << "\"activeViews\"" << ":" << this->getActiveViews() << ",";
+
+ oss << "\"views\"" << ":[";
+ std::string separator = "";
+ for (auto view : this->getViews())
+ {
+ oss << separator << "\"";
+ if(view.second.isExpired())
+ {
+ oss << "-";
+ }
+ oss << view.first << "\"";
+ separator = ",";
+ }
+ oss << "],";
+
+ oss << "\"lastActivity\"" << ":" << this->_lastActivity;
+ oss << "}";
+ return std::make_pair(ct, oss.str());
+}
+
+const std::string Document::getHistory() const
+{
+ std::ostringstream oss;
+ oss << "{";
+ oss << "\"docKey\"" << ":\"" << this->_docKey << "\",";
+ oss << "\"filename\"" << ":\"" << this->getFilename() << "\",";
+ oss << "\"start\"" << ":" << this->_start << ",";
+ oss << "\"end\"" << ":" << this->_end << ",";
+ oss << "\"pid\"" << ":" << this->getPid() << ",";
+ oss << "\"snapshots\"" << ":[";
+ std::string separator = "";
+ for (auto s : _snapshots)
+ {
+ oss << separator << s.second;
+ separator = ",";
+ }
+ oss << "]}";
+ return oss.str();
+}
+
+void Document::takeSnapshot()
+{
+ auto p = this->getSnapshot();
+ auto insPoint = _snapshots.upper_bound(p.first);
+ _snapshots.insert(insPoint, p);
+}
+
+std::string Document::to_string() const
+{
+ std::ostringstream oss;
+ std::string encodedFilename;
+ Poco::URI::encode(this->getFilename(), " ", encodedFilename);
+ oss << this->getPid() << ' '
+ << encodedFilename << ' '
+ << this->getActiveViews() << ' '
+ << this->getMemoryDirty() << ' '
+ << this->getElapsedTime() << ' '
+ << this->getIdleTime() << ' ';
+ return oss.str();
+}
+
bool Subscriber::notify(const std::string& message)
{
// If there is no socket, then return false to
@@ -106,6 +176,35 @@ void AdminModel::assertCorrectThread() const
assert(sameThread);
}
+AdminModel::~AdminModel()
+{
+ Log::debug("History:\n\n" + getAllHistory() + "\n");
+ Log::info("AdminModel dtor.");
+}
+
+std::string AdminModel::getAllHistory() const
+{
+ std::ostringstream oss;
+ oss << "{ \"documents\" : [";
+ std::string separator1 = "";
+ for (auto d : _documents)
+ {
+ oss << separator1;
+ oss << d.second.getHistory();
+ separator1 = ",";
+ }
+ oss << "], \"expiredDocuments\" : [";
+ separator1 = "";
+ for (auto ed : _expiredDocuments)
+ {
+ oss << separator1;
+ oss << ed.second.getHistory();
+ separator1 = ",";
+ }
+ oss << "]}";
+ return oss.str();
+}
+
std::string AdminModel::query(const std::string& command)
{
assertCorrectThread();
@@ -281,6 +380,7 @@ void AdminModel::addDocument(const std::string& docKey, Poco::Process::PID pid,
const auto ret = _documents.emplace(docKey, Document(docKey, pid, filename));
ret.first->second.addView(sessionId);
+ ret.first->second.takeSnapshot();
LOG_DBG("Added admin document [" << docKey << "].");
std::string encodedFilename;
@@ -329,11 +429,12 @@ void AdminModel::removeDocument(const std::string& docKey, const std::string& se
<< sessionId;
notify(oss.str());
- // TODO: The idea is to only expire the document and keep the history
+ // The idea is to only expire the document and keep the history
// of documents open and close, to be able to give a detailed summary
- // to the admin console with views. For now, just remove the document.
+ // to the admin console with views.
if (docIt->second.expireView(sessionId) == 0)
{
+ _expiredDocuments.emplace(*docIt);
_documents.erase(docIt);
}
}
@@ -355,9 +456,11 @@ void AdminModel::removeDocument(const std::string& docKey)
{
// Notify the subscribers
notify(msg + pair.first);
+ docIt->second.expireView(pair.first);
}
LOG_DBG("Removed admin document [" << docKey << "].");
+ _expiredDocuments.emplace(*docIt);
_documents.erase(docIt);
}
}
@@ -413,14 +516,7 @@ std::string AdminModel::getDocuments() const
{
if (!it.second.isExpired())
{
- std::string encodedFilename;
- Poco::URI::encode(it.second.getFilename(), " ", encodedFilename);
- oss << it.second.getPid() << ' '
- << encodedFilename << ' '
- << it.second.getActiveViews() << ' '
- << it.second.getMemoryDirty() << ' '
- << it.second.getElapsedTime() << ' '
- << it.second.getIdleTime() << " \n ";
+ oss << it.second.to_string() << "\n ";
}
}
@@ -436,6 +532,7 @@ void AdminModel::updateLastActivityTime(const std::string& docKey)
{
if (docIt->second.getIdleTime() >= 10)
{
+ docIt->second.takeSnapshot(); // I would like to keep the idle time
docIt->second.updateLastActivityTime();
notify("resetidle " + std::to_string(docIt->second.getPid()));
}
diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp
index 80f0437b..1b37f1a8 100644
--- a/wsd/AdminModel.hpp
+++ b/wsd/AdminModel.hpp
@@ -77,6 +77,12 @@ public:
bool updateMemoryDirty(int dirty);
int getMemoryDirty() const { return _memoryDirty; }
+ std::pair<std::time_t, std::string> getSnapshot() const;
+ const std::string getHistory() const;
+ void takeSnapshot();
+
+ std::string to_string() const;
+
private:
const std::string _docKey;
const Poco::Process::PID _pid;
@@ -92,6 +98,7 @@ private:
std::time_t _start;
std::time_t _lastActivity;
std::time_t _end = 0;
+ std::map<std::time_t,std::string> _snapshots;
};
/// An Admin session subscriber.
@@ -144,10 +151,7 @@ public:
LOG_INF("AdminModel ctor.");
}
- ~AdminModel()
- {
- LOG_INF("AdminModel dtor.");
- }
+ ~AdminModel();
/// All methods here must be called from the Admin socket-poll
void setThreadOwner(const std::thread::id &id) { _owner = id; }
@@ -157,6 +161,7 @@ public:
void assertCorrectThread() const;
std::string query(const std::string& command);
+ std::string getAllHistory() const;
/// Returns memory consumed by all active loolkit processes
unsigned getKitsMemoryUsage();
@@ -200,6 +205,7 @@ private:
private:
std::map<int, Subscriber> _subscribers;
std::map<std::string, Document> _documents;
+ std::map<std::string, Document> _expiredDocuments;
/// The last N total memory Dirty size.
std::list<unsigned> _memStats;
diff --git a/wsd/protocol.txt b/wsd/protocol.txt
index e686430b..b2404a70 100644
--- a/wsd/protocol.txt
+++ b/wsd/protocol.txt
@@ -490,6 +490,40 @@ documents
Queries the server for list of opened documents. See `documents` command
in admin -> client section for format of the response message
+history
+
+ Queries the server for list of opened and expired documents with their
+ snapshots. Returns a json object and it looks like:
+
+ { "History" :
+ {
+ "documents": [
+ {
+ "filename":"hello-world.odt",
+ "start":1492104619,
+ "end":1492104680,
+ "pid":12302,
+ "snapshots": [
+ {
+ "creationTime":1492104619,
+ "memoryDirty":0,
+ "activeViews":1,
+ "views":["0008", ...],
+ "lastActivity":1492104619
+ },
+ {
+ ...
+ }
+ ]
+ },
+ {
+ ...
+ }
+ ],
+ "expiredDocuments" : [...]
+ }
+ }
+
total_mem
Queries for total memory being consumed by the server in kilobytes.
More information about the Libreoffice-commits
mailing list