引言
現在許多的項目都需要定時的服務進行支撐,而我們經常用到的定時服務就是Quartz任務調度了。不過我們在使用定時Job進行獲取的時候,有時候我們就需要記錄一下自定義的日志,甚至我們還會對執行定時Job腳本中,本身的線程啟動和觸發器等相關信息進行記錄,這就用到了Common.Logging.log4net了,但同時它在控制台上輸出相應信息的同時,並不能對這些信息進行日志文件的記錄與存儲。
有關log4net的相關使用,詳情請看之前的博文:http://www.cnblogs.com/huanghzm/p/4754890.html
而本文的主要目的就是處理Quartz系統日志與log4net的相互結合,最后附帶說明了利用Topshlef坐直windows服務。
准備
1、安裝指定的程序包
Install-Package Quartz
Install-Package Common.Logging.Log4Net1211(安裝這個的時候會自定安裝其依賴項,即Log4Net)
Install-Package Topshelf
2、配置文件設置
<configSections>
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<common>
<logging>
<factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net1211">
<arg key="configType" value="INLINE" />
</factoryAdapter>
</logging>
</common>
<log4net>
<!--錯誤日志-->
<!--自定義錯誤異常-->
<appender name="CustomExAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\LogCustomEx\\" />
<param name="AppendToFile" value="true" />
<param name="MaxFileSize" value="10240" />
<param name="MaxSizeRollBackups" value="100" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" />
<param name="RollingStyle" value="Date" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日志級別: %-5level %n日志描述:%message%newline %n" />
</layout>
</appender>
<appender name="ErrorExAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\LogErrorEx\\" />
<param name="AppendToFile" value="true" />
<param name="MaxFileSize" value="10240" />
<param name="MaxSizeRollBackups" value="100" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" />
<param name="RollingStyle" value="Date" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日志級別: %-5level %n日志描述:%message%newline %n" />
</layout>
</appender>
<!--CustomEx日志-->
<logger name="LogCustomEx">
<level value="INFO" />
<appender-ref ref="CustomExAppender" />
</logger>
<!--Error日志-->
<logger name="LogErrorEx">
<level value="ERROR" />
<appender-ref ref="ErrorExAppender" />
</logger>
<!--服務執行日志-->
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\ServerLog\\" />
<param name="AppendToFile" value="true" />
<param name="MaxFileSize" value="10240" />
<param name="MaxSizeRollBackups" value="100" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" />
<param name="RollingStyle" value="Date" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>
</appender>
<!-- 控制台前台顯示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender>
<root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>
</log4net>
讓世界跑起來
1、配置相關Job類(JobInfo[對象]、JobType[類型]、JobInfoList[觸發器、時間]) 名稱、觸發器、群組、類型(根據不同的類型執行不同的Job內容)
public class JobInfo { public JobInfo(string jobName, string group, string trigger, JobType jobType) { if (jobName == null || trigger == null || group == null) { throw new ArgumentNullException("jobName"); } this.JobName = jobName; this.Trigger = trigger; this.Group = group; this.JobType = jobType; } /// <summary> /// 名稱 /// </summary> public string JobName { get; set; } /// <summary> /// Job的觸發器 cron表達式 /// </summary> public string Trigger { get; set; } /// <summary> /// 群組 /// </summary> public string Group { get; set; } /// <summary> /// Job類型 /// </summary> public JobType JobType { get; set; } } /// <summary> /// Job類型枚舉 /// </summary> public enum JobType { /// <summary> /// 任務1 /// </summary> Job1 = 1, /// <summary> /// 任務2 /// </summary> Job2 = 2 }
public class JobInfoList { /// <summary> /// 腳本服務組 /// </summary> public static List<JobInfo> JobList_ZhongShanHos = new List<JobInfo> { new JobInfo("任務1", "測試腳本", "*/5 * * * * ?", JobType.Job1), new JobInfo("任務2", "測試腳本", "*/7 * * * * ?", JobType.Job2) }; }
2、配置具體的Job內容與需要輸出的自定義日志,這里的日志使用log4net作為記錄 (TestJob.cs)
public class TestJob : IJob { private static readonly log4net.ILog LogInfo = log4net.LogManager.GetLogger("LogCustomEx"); private static readonly log4net.ILog LogError = log4net.LogManager.GetLogger("LogError"); public void Execute(IJobExecutionContext context) { var map = context.JobDetail.JobDataMap; var jobInfo = map["KEY"] as JobInfo; if (jobInfo == null) { return; } //記錄日志 LogInfo.Info("\n【服務已啟動】" + "\n【啟動組】:" + jobInfo.Group + "\n【啟動名稱】:" + jobInfo.JobName + "\n【啟動時間】:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); try { switch (jobInfo.JobType) { //基礎信息 case JobType.Job1: LogInfo.Info("這是任務1"); break; case JobType.Job2: LogInfo.Info("這是任務2"); break; default: break; } } catch (Exception ex) { //記錄日志 LogError.Error("\n【服務執行出錯】" + "\n【啟動組】:" + jobInfo.Group + "\n【啟動名稱】:" + jobInfo.JobName + "\n【時間】:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n【錯誤信息】:" + ex.Message); return; } } }
3、配置Job執行方法
public sealed class ServerRunner : ServiceControl, ServiceSuspend { private readonly IScheduler scheduler; public ServerRunner() { scheduler = StdSchedulerFactory.GetDefaultScheduler(); } public bool Start(HostControl hostControl) { var jobList = new List<JobInfo>(); //配置JobList任務 jobList.AddRange(JobInfoList.JobList_ZhongShanHos); jobList.ForEach( x => { var dic = new Dictionary<string, JobInfo> { { "KEY", x } }; var map = new JobDataMap(dic); var job = JobBuilder.Create<TestJob>() .WithIdentity(x.JobName, x.Group) .UsingJobData(map) .RequestRecovery() .Build(); var trigger = TriggerBuilder.Create() .WithIdentity(x.JobName, x.Group) .WithCronSchedule(x.Trigger) .Build(); scheduler.ScheduleJob(job, trigger); }); scheduler.Start(); return true; } public bool Stop(HostControl hostControl) { scheduler.Shutdown(false); return true; } public bool Continue(HostControl hostControl) { scheduler.ResumeAll(); return true; } public bool Pause(HostControl hostControl) { scheduler.PauseAll(); return true; } }
4、配置入口文件
class Program { static void Main(string[] args) { //配置Log4日志 log4net.Config.XmlConfigurator.Configure(); //Windows服務 HostFactory.Run(x => { x.UseLog4Net(); x.Service<ServerRunner>(); x.SetDescription("Quartz日志記錄服務"); x.SetDisplayName("Quartz"); x.SetServiceName("QuartzLog"); x.EnablePauseAndContinue(); }); } }
至此,基本的所有配置就這樣完成了,只要運行,就可以看到對應的服務的信息了。

日志信息也記錄在對應的(前面說設計的文檔中)按照相面的代碼選定的地址是根目錄文件,如圖所示:

windows服務
制作windows服務,非常簡單,只要調出cmd命令行,cd到指定文件的目錄,輸入應用程序名+install就可以,卸載的話就輸入uninstall就可以了。如圖所示:

源代碼地址:GitHub
鏈接:https://github.com/JaminHuang/QuartzLog.git
