Implemented live monitor of the logs

This commit is contained in:
Kenneth Skovhede
2014-08-01 11:18:10 +02:00
parent 5e24f0968b
commit ddbd689089
9 changed files with 221 additions and 39 deletions
+1
View File
@@ -116,6 +116,7 @@
<Compile Include="WebServer\ControlMethods\AddOrUpdateBackup.cs" />
<Compile Include="WebServer\ControlMethods\GetBackup.cs" />
<Compile Include="UpdatePollThread.cs" />
<Compile Include="LogWriteHandler.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+18 -11
View File
@@ -108,6 +108,11 @@ namespace Duplicati.Server
/// </summary>
public static long LastDataUpdateID = 0;
/// <summary>
/// The log redirect handler
/// </summary>
public static LogWriteHandler LogHandler = new LogWriteHandler();
public static int ServerPort
{
get
@@ -218,11 +223,6 @@ namespace Duplicati.Server
}
#endif
if (commandlineOptions.ContainsKey("log-level"))
foreach(string s in Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType)))
if (s.Equals(commandlineOptions["log-level"].Trim(), StringComparison.InvariantCultureIgnoreCase))
Duplicati.Library.Logging.Log.LogLevel = (Duplicati.Library.Logging.LogMessageType)Enum.Parse(typeof(Duplicati.Library.Logging.LogMessageType), s);
//Set the %DUPLICATI_HOME% env variable, if it is not already set
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(DATAFOLDER_ENV_NAME)))
{
@@ -278,11 +278,20 @@ namespace Duplicati.Server
}
}
// Setup the log redirect
Duplicati.Library.Logging.Log.CurrentLog = Program.LogHandler;
if (commandlineOptions.ContainsKey("log-file"))
{
if (System.IO.File.Exists(commandlineOptions["log-file"]))
System.IO.File.Delete(commandlineOptions["log-file"]);
Duplicati.Library.Logging.Log.CurrentLog = new Duplicati.Library.Logging.StreamLog(commandlineOptions["log-file"]);
var loglevel = Duplicati.Library.Logging.LogMessageType.Error;
if (commandlineOptions.ContainsKey("log-level"))
Enum.TryParse<Duplicati.Library.Logging.LogMessageType>(commandlineOptions["log-level"], true, out loglevel);
Program.LogHandler.SetServerFile(commandlineOptions["log-file"], loglevel);
}
Version sqliteVersion = new Version((string)Duplicati.Library.SQLiteHelper.SQLiteLoader.SQLiteConnectionType.GetProperty("SQLiteVersion").GetValue(null, null));
@@ -418,11 +427,9 @@ namespace Duplicati.Server
try { PingPongThread.Abort(); }
catch { }
#if DEBUG
//Flush the file
using (Duplicati.Library.Logging.Log.CurrentLog as Duplicati.Library.Logging.StreamLog)
Duplicati.Library.Logging.Log.CurrentLog = null;
#endif
if (LogHandler != null)
LogHandler.Dispose();
}
}
+16
View File
@@ -286,6 +286,21 @@ namespace Duplicati.Server
if (data.ExtraOptions != null)
foreach(var k in data.ExtraOptions)
options[k.Key] = k.Value;
if (options.ContainsKey("log-file"))
{
var file = options["log-file"];
string o;
Library.Logging.LogMessageType level;
options.TryGetValue("log-level", out o);
Enum.TryParse<Library.Logging.LogMessageType>(o, true, out level);
options.Remove("log-file");
options.Remove("log-level");
Program.LogHandler.SetOperationFile(file, level);
}
using(var controller = new Duplicati.Library.Main.Controller(backup.TargetURL, options, sink))
{
@@ -365,6 +380,7 @@ namespace Duplicati.Server
finally
{
((RunnerData)data).Controller = null;
Program.LogHandler.RemoveOperationFile();
}
}
+19 -2
View File
@@ -60,6 +60,7 @@ namespace Duplicati.Server.WebServer
SUPPORTED_METHODS.Add("get-license-data", GetLicenseData);
SUPPORTED_METHODS.Add("get-changelog", GetChangelog);
SUPPORTED_METHODS.Add("locate-uri-db", LocateUriDb);
SUPPORTED_METHODS.Add("poll-log-messages", PollLogMessages);
}
public override bool Process (HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
@@ -349,7 +350,7 @@ namespace Duplicati.Server.WebServer
bw.OutputOK();
}
catch (Duplicati.Library.Interface.FolderMissingException fex)
catch (Duplicati.Library.Interface.FolderMissingException)
{
ReportError(response, bw, "missing-folder");
}
@@ -403,7 +404,8 @@ namespace Duplicati.Server.WebServer
GenericModules = Serializable.ServerSettings.GenericModules,
WebModules = Serializable.ServerSettings.WebModules,
ConnectionModules = Serializable.ServerSettings.ConnectionModules,
UsingAlternateUpdateURLs = Duplicati.Library.AutoUpdater.AutoUpdateSettings.UsesAlternateURLs
UsingAlternateUpdateURLs = Duplicati.Library.AutoUpdater.AutoUpdateSettings.UsesAlternateURLs,
LogLevels = Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType))
});
}
@@ -649,6 +651,21 @@ namespace Duplicati.Server.WebServer
});
}
private void PollLogMessages(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
{
HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
var level_str = input["level"].Value ?? "";
var id_str = input["id"].Value ?? "";
Library.Logging.LogMessageType level;
long id;
long.TryParse(id_str, out id);
Enum.TryParse(level_str, true, out level);
bw.OutputOK(Program.LogHandler.AfterID(id, level));
}
private void SendCommand(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
{
HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
+20
View File
@@ -90,6 +90,15 @@
</div>
</script>
<script id="live-log-data-template" type="text/x-jquery-tmpl">
<div class="log-entry">
<div class="log-id">${BackupID}</div>
<div class="log-timestamp" title="${When}">${When}</div>
<div class="log-message">${Message}</div>
<div class="log-exception">${Exception}</div>
</div>
</script>
<script id="log-backup-general-template" type="text/x-jquery-tmpl">
<div class="log-entry">
<div class="log-operationid">${BackupID}</div>
@@ -460,6 +469,17 @@
<div id="folder-browse-dialog" class="modal-dialog" title="Choose folder"></div>
<div id="log-dialog" class="modal-dialog" title="Log data">
<ul>
<li><a href="#log-tab-stored">Stored</a></li>
<li><a href="#log-tab-live">Live</a></li>
</ul>
<div id="log-tab-stored">
</div>
<div id="log-tab-live">
<select id="log-tab-live-level"></select>
</div>
</div>
@@ -999,7 +999,7 @@ $(document).ready(function() {
};
$('#edit-dialog-form').find('input').change(setStateModified);
$('#edit-dialog-form').find('option').change(setStateModified);
$('#edit-dialog-form').find('select').change(setStateModified);
$('#edit-dialog-form').find('textarea').change(setStateModified);
$('#use-scheduled-run').change(function() {
+121 -25
View File
@@ -1,86 +1,174 @@
$(document).ready(function() {
var appdatacallback = function(data, tag) {
$.tmpl($('#log-data-template'), data).appendTo(tag);
tag.find('.log-exception').each(function(i, e) {
var td = $.tmpl($('#log-data-template'), data);
td.appendTo(tag);
td.find('.log-exception').each(function(i, e) {
$(e).html(nl2br($(e).html()));
});
tag.find('.log-exception').click(function(e) {
td.find('.log-exception').click(function(e) {
e.bubbles = false;
return false;
});
tag.find('.log-timestamp').each(function(i, e) {
td.find('.log-timestamp').each(function(i, e) {
$(e).text((new Date(parseInt($(e).attr('title')))).toLocaleString());
});
tag.find('.log-entry').click(function(e) {
$(e.target).closest('.log-entry').toggleClass('expanded');
td.click(function(e) {
$(this).toggleClass('expanded');
});
};
var livedatacallback = function(data, tag) {
var td = $.tmpl($('#live-log-data-template'), data)
td.appendTo(tag);
td.find('.log-exception').each(function(i, e) {
$(e).html(nl2br($(e).html()));
});
td.find('.log-exception').click(function(e) {
e.bubbles = false;
return false;
});
td.find('.log-timestamp').each(function(i, e) {
$(e).text(new Date($(e).attr('title')).toLocaleString());
});
td.click(function(e) {
$(this).toggleClass('expanded');
});
tag.parent().scrollTop(tag.parent().height());
};
var generaldatacallback = function(data, tag) {
$.tmpl($('#log-backup-general-template'), data).appendTo(tag);
tag.find('.log-exception').each(function(i, e) {
var td = $.tmpl($('#log-backup-general-template'), data)
td.appendTo(tag);
td.find('.log-exception').each(function(i, e) {
$(e).html(nl2br($(e).html()));
});
tag.find('.log-message').each(function(i, e) {
td.find('.log-message').each(function(i, e) {
$(e).html(nl2br($(e).html()));
});
tag.find('.log-exception').click(function(e) {
td.find('.log-exception').click(function(e) {
return e.bubbles = false;
});
tag.find('.log-message').click(function(e) {
td.find('.log-message').click(function(e) {
return e.bubbles = false;
});
tag.find('.log-timestamp').each(function(i, e) {
td.find('.log-timestamp').each(function(i, e) {
$(e).text((new Date(parseInt($(e).attr('title')))).toLocaleString());
});
tag.find('.log-entry').click(function(e) {
$(e.target).closest('.log-entry').toggleClass('expanded');
td.click(function(e) {
$(this).toggleClass('expanded');
});
};
var remotedatacallback = function(data, tag) {
$.tmpl($('#log-backup-remote-template'), data).appendTo(tag);
tag.find('.log-data').each(function(i, e) {
var td = $.tmpl($('#log-backup-remote-template'), data);
td.appendTo(tag);
td.find('.log-data').each(function(i, e) {
$(e).html(nl2br($(e).html()));
});
tag.find('.log-data').click(function(e) {
td.find('.log-data').click(function(e) {
return e.bubbles = false;
});
tag.find('.log-timestamp').each(function(i, e) {
td.find('.log-timestamp').each(function(i, e) {
$(e).text((new Date(parseInt($(e).attr('title')))).toLocaleString());
});
tag.find('.log-entry').click(function(e) {
td.click(function(e) {
$(e.target).closest('.log-entry').toggleClass('expanded');
});
};
var refreshRunning = false;
var refreshId = 0;
var refreshLiveData = function() {
if (refreshRunning)
return;
var v = $('#log-tab-live-level').val();
if (v == '' || v == 'disabled')
return;
if (!$('#log-dialog').dialog('isOpen'))
return;
refreshRunning = true;
APP_DATA.callServer({'action': 'poll-log-messages', 'level': v, 'id': refreshId},
function(data) {
for(var n in data)
refreshId = Math.max(refreshId, data[n].ID);
refreshRunning = false;
livedatacallback(data, $('#log-tab-live'));
setTimeout(refreshLiveData, 3000);
},
function() {
refreshRunning = false;
setTimeout(refreshLiveData, 1000);
});
};
$.showAppLog = function() {
var dlg_buttons = $('#log-dialog').parent().find('.ui-dialog-buttonpane').find('.ui-button');
$('#log-dialog').dialog('open');
var data = $('#log-dialog').data('log');
var data = $('#log-tab-stored').data('log');
if (!data) {
data = {
first: null,
last: null
};
$('#log-dialog').data('log', data);
$('#log-tab-stored').data('log', data);
}
if (data.first == null) {
$('#log-dialog').empty();
$('#log-tab-stored').empty();
APP_DATA.callServer({'action': 'read-log', 'pagesize': 100}, function(data) {
appdatacallback(data, $('#log-dialog'));
appdatacallback(data, $('#log-tab-stored'));
});
};
var loglevel = $('#log-tab-live-level');
loglevel.empty();
$('#log-tab-live').find('.log-entry').remove();
loglevel.change(function() {
refreshId = 0;
var v = $('#log-tab-live-level').val();
if (v == '' || v == 'disabled')
return;
$('#log-tab-live').find('.log-entry').remove();
refreshLiveData();
});
APP_DATA.getServerConfig(function(server_config) {
loglevel.append($('<option></option>')
.attr('value', 'disabled')
.text('Disabled'));
for(var n in server_config.LogLevels)
loglevel.append($('<option></option>')
.attr('value',server_config.LogLevels[n])
.text(server_config.LogLevels[n]));
}, function() { alert('Failed to read server data'); });
};
$.showBackupLog = function(id) {
@@ -91,8 +179,14 @@ $(document).ready(function() {
$('<div id="restore-search-loader" class="small-loader-icon">').appendTo($('#backup-log-tab-general'));
$('<div id="restore-search-loader" class="small-loader-icon">').appendTo($('#backup-log-tab-remote'));
var loglevel = $('#backup-log-live-level');
loglevel.empty();
loglevel.change(refreshLiveData);
$('#backup-log-dialog').dialog('open');
APP_DATA.callServer({'action': 'read-log', 'pagesize': 100, 'id': id, 'remotelog': false}, function(generaldata) {
APP_DATA.callServer({'action': 'read-log', 'pagesize': 100, 'id': id, 'remotelog': true}, function(remotedata) {
$('#backup-log-tab-general').empty();
@@ -100,11 +194,13 @@ $(document).ready(function() {
generaldatacallback(generaldata, $('#backup-log-tab-general'));
remotedatacallback(remotedata, $('#backup-log-tab-remote'));
}, function() { alert('Failed to read log data'); });
}, function() { alert('Failed to read log data'); });
};
$('#log-dialog').tabs({ active: 0 });
$('#log-dialog').dialog({
minWidth: 320,
width: $('body').width > 600 ? 320 : 600,
@@ -115,7 +211,7 @@ $(document).ready(function() {
closeOnEscape: true,
buttons: [
{ text: 'Close', disabled: false, click: function(event, ui) {
$('#log-dialog').dialog('close');
$(this).dialog('close');
}}
]
});
@@ -131,7 +227,7 @@ $(document).ready(function() {
closeOnEscape: true,
buttons: [
{ text: 'Close', disabled: false, click: function(event, ui) {
$('#backup-log-dialog').dialog('close');
$(this).dialog('close');
}}
]
});
@@ -27,6 +27,23 @@
padding-right: 5px;
}
#log-tab-live .log-entry .log-message
{
display: inline;
}
#log-tab-live .log-entry
{
height: 1.2em;
overflow: hidden;
}
#log-tab-live .log-entry.expanded
{
height: auto;
}
@@ -277,6 +277,14 @@ div.main-icon-plus {
border-top-right-radius: 0px;
}
#log-dialog {
padding: 0px;
border: 0px none;
width: 100%;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
}
.ui-dialog-titlebar {
border-bottom-right-radius: 0px;
border-bottom-left-radius: 0px;