diff --git a/QuartzNetWebConsole/Controllers/LogController.cs b/QuartzNetWebConsole/Controllers/LogController.cs new file mode 100644 index 0000000..07df649 --- /dev/null +++ b/QuartzNetWebConsole/Controllers/LogController.cs @@ -0,0 +1,15 @@ +using System; +using System.Web; +using MiniMVC; + +namespace QuartzNetWebConsole.Controllers { + public class LogController : Controller { + private readonly ILogger logger = Setup.Logger; + + public override IResult Execute(HttpContextBase context) { + if (logger == null) + return new RawResult("No logger defined"); + return new ViewResult(logger, ViewName); + } + } +} \ No newline at end of file diff --git a/QuartzNetWebConsole/ILogger.cs b/QuartzNetWebConsole/ILogger.cs new file mode 100644 index 0000000..6ccc4c5 --- /dev/null +++ b/QuartzNetWebConsole/ILogger.cs @@ -0,0 +1,6 @@ +using System.Collections.Generic; +using Quartz; + +namespace QuartzNetWebConsole { + public interface ILogger: ISchedulerListener, IJobListener, ITriggerListener, IEnumerable {} +} \ No newline at end of file diff --git a/QuartzNetWebConsole/LogEntry.cs b/QuartzNetWebConsole/LogEntry.cs new file mode 100644 index 0000000..67736cf --- /dev/null +++ b/QuartzNetWebConsole/LogEntry.cs @@ -0,0 +1,21 @@ +using System; + +namespace QuartzNetWebConsole { + public class LogEntry { + private readonly DateTime timestamp; + private readonly string description; + + public DateTime Timestamp { + get { return timestamp; } + } + + public string Description { + get { return description; } + } + + public LogEntry(string description) { + timestamp = DateTime.Now; + this.description = description; + } + } +} \ No newline at end of file diff --git a/QuartzNetWebConsole/MemoryLogger.cs b/QuartzNetWebConsole/MemoryLogger.cs new file mode 100644 index 0000000..a7d85cd --- /dev/null +++ b/QuartzNetWebConsole/MemoryLogger.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Quartz; +using QuartzNetWebConsole.Utils; + +namespace QuartzNetWebConsole { + public class MemoryLogger : ILogger { + private readonly CircularBuffer entries; + + public MemoryLogger(int capacity) { + entries = new CircularBuffer(capacity); + } + + public void JobScheduled(Trigger trigger) { + var desc = string.Format("Job {0} scheduled with trigger {1}", trigger.FullJobName, Describe(trigger)); + entries.Add(new LogEntry(desc)); + } + + private string Describe(Trigger trigger) { + var cronTrigger = trigger as CronTrigger; + var cronDesc = cronTrigger == null ? null : cronTrigger.CronExpressionString; + + var simpleTrigger = trigger as SimpleTrigger; + var simpleDesc = simpleTrigger == null ? null : string.Format("interval {0}, repeat count {1}", simpleTrigger.RepeatInterval, simpleTrigger.RepeatCount); + return string.Format("{0}.{1} ({2}) {3}{4}", trigger.Group, trigger.Name, trigger.GetType(), cronDesc, simpleDesc); + } + + public void JobUnscheduled(string triggerName, string triggerGroup) { + entries.Add(new LogEntry(string.Format("Trigger removed: {0}.{1}", triggerGroup, triggerName))); + } + + public void TriggerFinalized(Trigger trigger) { + entries.Add(new LogEntry(string.Format("Trigger finalized: {0}", Describe(trigger)))); + } + + public void TriggersPaused(string triggerName, string triggerGroup) { + entries.Add(new LogEntry(string.Format("Trigger paused: {0}.{1}", triggerGroup, triggerName))); + } + + public void TriggersResumed(string triggerName, string triggerGroup) { + entries.Add(new LogEntry(string.Format("Trigger resumed: {0}.{1}", triggerGroup, triggerName))); + } + + public void JobsPaused(string jobName, string jobGroup) { + entries.Add(new LogEntry(string.Format("Job paused: {0}.{1}", jobGroup, jobName))); + } + + public void JobsResumed(string jobName, string jobGroup) { + entries.Add(new LogEntry(string.Format("Job resumed: {0}.{1}", jobGroup, jobName))); + } + + public void SchedulerError(string msg, SchedulerException cause) { + entries.Add(new LogEntry(string.Format("Scheduler error: {0}\n{1}", msg, cause))); + } + + public void SchedulerShutdown() { + entries.Add(new LogEntry("Scheduler shutdown")); + } + + public void JobToBeExecuted(JobExecutionContext context) { + entries.Add(new LogEntry(string.Format("Job to be executed: {0}", Describe(context)))); + } + + private string Describe(JobExecutionContext context) { + return string.Format("{0} (trigger {1})", context.JobDetail.FullName, Describe(context.Trigger)); + } + + public void JobExecutionVetoed(JobExecutionContext context) { + entries.Add(new LogEntry(string.Format("Job execution vetoed: {0}", Describe(context)))); + } + + public void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { + var description = string.Format("Job was executed: {0}", Describe(context)); + if (jobException != null) + description += "\nwith exception: " + jobException; + entries.Add(new LogEntry(description)); + } + + public void TriggerFired(Trigger trigger, JobExecutionContext context) { + entries.Add(new LogEntry(string.Format("Trigger fired: {0}", Describe(context)))); + } + + public bool VetoJobExecution(Trigger trigger, JobExecutionContext context) { + return false; + } + + public void TriggerMisfired(Trigger trigger) { + entries.Add(new LogEntry(string.Format("Trigger misfired: {0}", Describe(trigger)))); + } + + public void TriggerComplete(Trigger trigger, JobExecutionContext context, SchedulerInstruction triggerInstructionCode) { + entries.Add(new LogEntry(string.Format("Trigger complete: {0}", Describe(context)))); + } + + string ITriggerListener.Name { + get { return GetType().Name; } + } + + string IJobListener.Name { + get { return GetType().Name; } + } + + public IEnumerator GetEnumerator() { + return entries.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/QuartzNetWebConsole/QuartzNetWebConsole.csproj b/QuartzNetWebConsole/QuartzNetWebConsole.csproj index 9038a7c..dbacc6f 100644 --- a/QuartzNetWebConsole/QuartzNetWebConsole.csproj +++ b/QuartzNetWebConsole/QuartzNetWebConsole.csproj @@ -61,7 +61,11 @@ + + + + diff --git a/QuartzNetWebConsole/Setup.cs b/QuartzNetWebConsole/Setup.cs index 93f5d3a..a7eef6d 100644 --- a/QuartzNetWebConsole/Setup.cs +++ b/QuartzNetWebConsole/Setup.cs @@ -3,7 +3,22 @@ namespace QuartzNetWebConsole { public static class Setup { - public static Func Scheduler { get; set;} + public static Func Scheduler { get; set; } + + public static void SetLogger(ILogger logger) { + var scheduler = Scheduler(); + if (Logger != null) { + scheduler.RemoveGlobalJobListener(logger); + scheduler.RemoveGlobalTriggerListener(logger); + scheduler.RemoveSchedulerListener(logger); + } + scheduler.AddGlobalJobListener(logger); + scheduler.AddGlobalTriggerListener(logger); + scheduler.AddSchedulerListener(logger); + Logger = logger; + } + + public static ILogger Logger { get; private set; } static Setup() { Scheduler = () => { diff --git a/SampleApp/Global.asax.cs b/SampleApp/Global.asax.cs index 7b35307..1462115 100644 --- a/SampleApp/Global.asax.cs +++ b/SampleApp/Global.asax.cs @@ -2,6 +2,7 @@ using System.Web; using Quartz; using Quartz.Impl; +using QuartzNetWebConsole; namespace SampleApp { public class Global : HttpApplication { @@ -24,7 +25,8 @@ protected void Application_Start(object sender, EventArgs e) { scheduler.ScheduleJob(cron); scheduler.AddCalendar("myCalendar", new DummyCalendar {Description = "dummy calendar"}, false, false); - QuartzNetWebConsole.Setup.Scheduler = () => scheduler; + Setup.Scheduler = () => scheduler; + Setup.SetLogger(new MemoryLogger(1000)); var engine = new MiniMVC.ExternalVelocityEngine(); MiniMVC.Setup.TemplateEngine = () => engine; } diff --git a/SampleApp/Resources/QuartzNetWebConsole.Resources.Log.html b/SampleApp/Resources/QuartzNetWebConsole.Resources.Log.html new file mode 100644 index 0000000..bad9783 --- /dev/null +++ b/SampleApp/Resources/QuartzNetWebConsole.Resources.Log.html @@ -0,0 +1,28 @@ + + + + Quartz.Net Console - Log + + + +

Scheduler log

+ + + + + + #foreach ($i in $model) + #before + + #even + class="alt"> + #each + + + + #end +
Date / TimeDescription
$i.Timestamp$i.Description
+ + \ No newline at end of file