Added progress messaging, using info logging

Also extension methods for complete and failed (for coloured UI messaging)
This commit is contained in:
Mark McDowall 2013-09-01 19:55:45 -07:00
parent eeda4e83f9
commit c928ccb201
21 changed files with 191 additions and 32 deletions

View File

@ -11,7 +11,7 @@ namespace NzbDrone.Api.Commands
public class CommandConnection : NzbDronePersistentConnection,
IHandleAsync<CommandStartedEvent>,
IHandleAsync<CommandCompletedEvent>,
IHandle<CommandFailedEvent>
IHandleAsync<CommandFailedEvent>
{
public override string Resource
{
@ -28,7 +28,7 @@ namespace NzbDrone.Api.Commands
BroadcastMessage(message.TrackedCommand);
}
public void Handle(CommandFailedEvent message)
public void HandleAsync(CommandFailedEvent message)
{
BroadcastMessage(message.TrackedCommand);
}

View File

@ -86,6 +86,9 @@
<Compile Include="Commands\CommandConnection.cs" />
<Compile Include="Config\NamingConfigResource.cs" />
<Compile Include="Config\NamingModule.cs" />
<Compile Include="ProgressMessaging\ProgressMessageConnection.cs" />
<Compile Include="ProgressMessaging\ProgressMessageModule.cs" />
<Compile Include="ProgressMessaging\ProgressMessageResource.cs" />
<Compile Include="EpisodeFiles\EpisodeFileModule.cs" />
<Compile Include="EpisodeFiles\EpisodeFileResource.cs" />
<Compile Include="Directories\DirectoryLookupService.cs" />

View File

@ -0,0 +1,24 @@
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Infrastructure;
using NzbDrone.Api.SignalR;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.ProgressMessaging;
namespace NzbDrone.Api.ProgressMessaging
{
public class ProgressMessageConnection : NzbDronePersistentConnection,
IHandleAsync<NewProgressMessageEvent>
{
public override string Resource
{
get { return "/ProgressMessage"; }
}
public void HandleAsync(NewProgressMessageEvent message)
{
var context = ((ConnectionManager)GlobalHost.ConnectionManager).GetConnection(GetType());
context.Connection.Broadcast(message.ProgressMessage);
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Extensions;
namespace NzbDrone.Api.ProgressMessaging
{
public class ProgressMessageModule : NzbDroneRestModule<ProgressMessageResource>
{
public ProgressMessageModule()
{
Get["/"] = x => GetAllMessages();
}
private Response GetAllMessages()
{
return new List<ProgressMessageResource>().AsResponse();
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.ProgressMessaging
{
public class ProgressMessageResource : RestResource
{
public DateTime Time { get; set; }
public String CommandId { get; set; }
public String Message { get; set; }
}
}

View File

@ -30,11 +30,11 @@ namespace NzbDrone.Common.Test.EventingTests
Mocker.GetMock<ITrackCommands>()
.Setup(c => c.TrackIfNew(It.IsAny<CommandA>()))
.Returns(new TrackedCommand(new CommandA(), CommandState.Running));
.Returns(new TrackedCommand(new CommandA(), ProcessState.Running));
Mocker.GetMock<ITrackCommands>()
.Setup(c => c.TrackIfNew(It.IsAny<CommandB>()))
.Returns(new TrackedCommand(new CommandB(), CommandState.Running));
.Returns(new TrackedCommand(new CommandB(), ProcessState.Running));
}
[Test]
@ -44,7 +44,7 @@ namespace NzbDrone.Common.Test.EventingTests
Mocker.GetMock<ITrackCommands>()
.Setup(c => c.TrackIfNew(commandA))
.Returns(new TrackedCommand(commandA, CommandState.Running));
.Returns(new TrackedCommand(commandA, ProcessState.Running));
Subject.PublishCommand(commandA);
@ -69,7 +69,7 @@ namespace NzbDrone.Common.Test.EventingTests
Mocker.GetMock<ITrackCommands>()
.Setup(c => c.TrackIfNew(commandA))
.Returns(new TrackedCommand(commandA, CommandState.Running));
.Returns(new TrackedCommand(commandA, ProcessState.Running));
Subject.PublishCommand(commandA);

View File

@ -13,7 +13,6 @@ namespace NzbDrone.Common.Instrumentation
return HashUtil.CalculateCrc(hashSeed);
}
public static string GetFormattedMessage(this LogEventInfo logEvent)
{
var message = logEvent.FormattedMessage;

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Common.Messaging.Tracking;
namespace NzbDrone.Common.Instrumentation
{
public static class LoggerExtensions
{
public static void Complete(this Logger logger, string message)
{
var logEvent = new LogEventInfo(LogLevel.Info, logger.Name, message);
logEvent.Properties.Add("Status", ProcessState.Completed);
logger.Log(logEvent);
}
public static void Complete(this Logger logger, string message, params object[] args)
{
var formattedMessage = String.Format(message, args);
Complete(logger, formattedMessage);
}
public static void Failed(this Logger logger, string message)
{
var logEvent = new LogEventInfo(LogLevel.Info, logger.Name, message);
logEvent.Properties.Add("Status", ProcessState.Failed);
logger.Log(logEvent);
}
public static void Failed(this Logger logger, string message, params object[] args)
{
var formattedMessage = String.Format(message, args);
Failed(logger, formattedMessage);
}
}
}

View File

@ -4,7 +4,6 @@
public interface IProcessMessageAsync : IProcessMessage { }
public interface IProcessMessage<TMessage> : IProcessMessage { }
public interface IProcessMessageAsync<TMessage> : IProcessMessageAsync { }

View File

@ -33,7 +33,7 @@ namespace NzbDrone.Common.Messaging.Tracking
return null;
}
var trackedCommand = new TrackedCommand(command, CommandState.Running);
var trackedCommand = new TrackedCommand(command, ProcessState.Running);
Store(trackedCommand);
return trackedCommand;
@ -45,7 +45,7 @@ namespace NzbDrone.Common.Messaging.Tracking
if (trackedCommand == null)
{
trackedCommand = new TrackedCommand(command, CommandState.Running);
trackedCommand = new TrackedCommand(command, ProcessState.Running);
Store(trackedCommand);
return new ExistingCommand(false, trackedCommand);
@ -57,7 +57,7 @@ namespace NzbDrone.Common.Messaging.Tracking
public TrackedCommand Completed(TrackedCommand trackedCommand, TimeSpan runtime)
{
trackedCommand.StateChangeTime = DateTime.UtcNow;
trackedCommand.State = CommandState.Completed;
trackedCommand.State = ProcessState.Completed;
trackedCommand.Runtime = runtime;
Store(trackedCommand);
@ -68,7 +68,7 @@ namespace NzbDrone.Common.Messaging.Tracking
public TrackedCommand Failed(TrackedCommand trackedCommand, Exception e)
{
trackedCommand.StateChangeTime = DateTime.UtcNow;
trackedCommand.State = CommandState.Failed;
trackedCommand.State = ProcessState.Failed;
trackedCommand.Exception = e;
Store(trackedCommand);
@ -94,7 +94,7 @@ namespace NzbDrone.Common.Messaging.Tracking
private List<TrackedCommand> Running(Type type = null)
{
var running = AllTracked().Where(i => i.State == CommandState.Running);
var running = AllTracked().Where(i => i.State == ProcessState.Running);
if (type != null)
{
@ -116,7 +116,7 @@ namespace NzbDrone.Common.Messaging.Tracking
public void Execute(TrackedCommandCleanupCommand message)
{
var old = AllTracked().Where(c => c.State != CommandState.Running && c.StateChangeTime < DateTime.UtcNow.AddMinutes(-5));
var old = AllTracked().Where(c => c.State != ProcessState.Running && c.StateChangeTime < DateTime.UtcNow.AddMinutes(-5));
foreach (var trackedCommand in old)
{

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Common.Messaging.Tracking
{
public enum ProcessState
{
Running,
Completed,
Failed
}
}

View File

@ -8,7 +8,7 @@ namespace NzbDrone.Common.Messaging.Tracking
public String Name { get; private set; }
public String Type { get; private set; }
public ICommand Command { get; private set; }
public CommandState State { get; set; }
public ProcessState State { get; set; }
public DateTime StateChangeTime { get; set; }
public TimeSpan Runtime { get; set; }
public Exception Exception { get; set; }
@ -17,7 +17,7 @@ namespace NzbDrone.Common.Messaging.Tracking
{
}
public TrackedCommand(ICommand command, CommandState state)
public TrackedCommand(ICommand command, ProcessState state)
{
Id = command.CommandId;
Name = command.GetType().Name;
@ -27,11 +27,4 @@ namespace NzbDrone.Common.Messaging.Tracking
StateChangeTime = DateTime.UtcNow;
}
}
public enum CommandState
{
Running = 0,
Completed = 1,
Failed = 2
}
}

View File

@ -92,6 +92,8 @@
<Compile Include="IEnumerableExtensions.cs" />
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
<Compile Include="Instrumentation\ExceptronTarget.cs" />
<Compile Include="Instrumentation\LoggerExtensions.cs" />
<Compile Include="Messaging\Tracking\ProcessState.cs" />
<Compile Include="Messaging\Tracking\CommandTrackingService.cs" />
<Compile Include="Messaging\Tracking\ExistingCommand.cs" />
<Compile Include="Messaging\Tracking\TrackedCommand.cs" />

View File

@ -1,5 +1,6 @@
using System.Linq;
using NLog;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
@ -38,7 +39,7 @@ namespace NzbDrone.Core.Indexers
var decisions = _downloadDecisionMaker.GetRssDecision(reports);
var qualifiedReports = _downloadApprovedReports.DownloadApproved(decisions);
_logger.Info("RSS Sync Completed. Reports found: {0}, Reports downloaded: {1}", reports.Count, qualifiedReports.Count());
_logger.Complete("RSS Sync Completed. Reports found: {0}, Reports downloaded: {1}", reports.Count, qualifiedReports.Count());
}
public void Execute(RssSyncCommand message)

View File

@ -221,7 +221,7 @@
<Compile Include="Instrumentation\DeleteLogFilesService.cs" />
<Compile Include="ProgressMessaging\NewProgressMessageEvent.cs" />
<Compile Include="ProgressMessaging\ProgressMessage.cs" />
<Compile Include="ProgressMessaging\ProgressMessagingTarget.cs" />
<Compile Include="ProgressMessaging\ProgressMessageTarget.cs" />
<Compile Include="Instrumentation\SetLoggingLevel.cs" />
<Compile Include="Jobs\TaskManager.cs" />
<Compile Include="Lifecycle\ApplicationShutdownRequested.cs" />

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.Messaging.Tracking;
namespace NzbDrone.Core.ProgressMessaging
{
@ -10,5 +8,6 @@ namespace NzbDrone.Core.ProgressMessaging
public DateTime Time { get; set; }
public String CommandId { get; set; }
public String Message { get; set; }
public ProcessState Status { get; set; }
}
}

View File

@ -4,17 +4,18 @@ using NLog;
using NLog.Layouts;
using NLog.Targets;
using NzbDrone.Common.Messaging;
using NzbDrone.Common.Messaging.Tracking;
using NzbDrone.Core.Lifecycle;
namespace NzbDrone.Core.ProgressMessaging
{
public class ProgressMessagingTarget : TargetWithLayout, IHandle<ApplicationStartedEvent>, IHandle<ApplicationShutdownRequested>
public class ProgressMessageTarget : TargetWithLayout, IHandle<ApplicationStartedEvent>, IHandle<ApplicationShutdownRequested>
{
private readonly IMessageAggregator _messageAggregator;
public LoggingRule Rule { get; set; }
public ProgressMessagingTarget(IMessageAggregator messageAggregator)
public ProgressMessageTarget(IMessageAggregator messageAggregator)
{
_messageAggregator = messageAggregator;
}
@ -55,10 +56,13 @@ namespace NzbDrone.Core.ProgressMessaging
return;
}
var status = logEvent.Properties.ContainsKey("Status") ? (ProcessState)logEvent.Properties["Status"] : ProcessState.Running;
var message = new ProgressMessage();
message.Time = logEvent.TimeStamp;
message.CommandId = commandId;
message.Message = logEvent.FormattedMessage;
message.Status = status;
_messageAggregator.PublishEvent(new NewProgressMessageEvent(message));
}

View File

@ -0,0 +1,40 @@
'use strict';
define(
[
'backbone',
'ProgressMessaging/ProgressMessageModel',
'Shared/Messenger',
'Mixins/backbone.signalr.mixin'
], function (Backbone, ProgressMessageModel, Messenger) {
var ProgressMessageCollection = Backbone.Collection.extend({
url : window.ApiRoot + '/progressmessage',
model: ProgressMessageModel
});
var collection = new ProgressMessageCollection().bindSignalR();
collection.signalRconnection.received(function (message) {
var type = getMessengerType(message.status);
Messenger.show({
id : message.commandId,
message: message.message,
type : type
});
});
var getMessengerType = function (status) {
switch (status) {
case 'completed':
return 'success';
case 'failed':
return 'error';
default:
return 'info';
}
}
return collection;
});

View File

@ -0,0 +1,8 @@
'use strict';
define(
[
'backbone'
], function (Backbone) {
return Backbone.Model.extend({
});
});

View File

@ -5,11 +5,12 @@ require(
'marionette',
'Controller',
'Series/SeriesCollection',
'ProgressMessaging/ProgressMessageCollection',
'Shared/Actioneer',
'Navbar/NavbarView',
'jQuery/RouteBinder',
'jquery'
], function (App, Marionette, Controller, SeriesCollection, Actioneer, NavbarView, RouterBinder, $) {
], function (App, Marionette, Controller, SeriesCollection, ProgressMessageCollection, Actioneer, NavbarView, RouterBinder, $) {
var Router = Marionette.AppRouter.extend({

View File

@ -105,7 +105,6 @@ define(
title : 'RSS Sync',
icon : 'icon-rss',
command : 'rsssync',
successMessage: 'RSS Sync Completed',
errorMessage : 'RSS Sync Failed!'
},
{