Журналы планировщика Quartz.net через log4net не поступают в правильный файл журнала

Я работаю над службой Windows, и эта служба имеет пять разных заданий, которые выполняются одновременно, поскольку есть планировщик, который использует библиотеку Quarts.Net и TopShelf для планирования этих заданий в определенный интервал времени. Проблема заключается в ведении журнала для каждого задания, библиотека log4Net используется для ведения журнала каждого задания в отдельный файл, и в файле app.config есть правильная конфигурация для каждого регистратора, но все же во время выполнения ведение журнала не выполняется в правильном файле журнала, когда все задания выполняются одновременно. Ниже приведен пример кода для этих заданий:

factory = new StdSchedulerFactory();
scheduler = factory.GetScheduler();

scheduler.JobFactory = new LoggerEnabledJobFactory() { AppLogger = LogManager.GetLogger("Job1") }; // in case of another job it will be "Job2"
 scheduler.ListenerManager.AddJobListener(new JobListener() { Name = "Job1Listener" });

IJobDetail jobDetails = JobBuilder.Create<ServiceJob1>().SetJobData(map).Build();

ITrigger trigger = TriggerBuilder.Create()
                                .WithSimpleSchedule(x =>
                                                        x.WithIntervalInSeconds(interval)
                                                        .RepeatForever().WithMisfireHandlingInstructionIgnoreMisfires()
                                                    )
                                .StartNow()
                                .WithIdentity("Job1TriggerGroup")
                                .Build();

scheduler.ScheduleJob(jobDetails, trigger);
scheduler.Start();

Ниже приведен пользовательский код JobFactory: (который уже был в коде)

public interface IloggerEnabledJob : IJob
    {
        ILog AppLogger{ get; set; }
    }

    public class LoggerEnabledJobFactory : IJobFactory
    {
        public ILog AppLogger { get; set; }

        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            var job = Activator.CreateInstance(bundle.JobDetail.JobType);            
            ((IloggerEnabledJob)job).AppLogger = AppLogger ;

            return (IJob)job;
        }

        public void ReturnJob(IJob job)
        {
        }
    }

Ниже приведен код класса "ServiceJob1":

public class ServiceJob1 : IloggerEnabledJob
{
   public ILog AppLogger { get; set; }

   public void Execute(IJobExecutionContext context)
        {
            try
            {
                // do something
            }
            catch (Exception ex)
            {
                Logger.Log(AppLogger, Logger.LogType.Error, "Exception : " + ex);
            }
        }
}

Приложение.config:

    <log4net>
        <root>
          <level value="INFO"/>
          <appender-ref ref="Job1FileAppender"/>
          <appender-ref ref="Job2FileAppender"/>
         </root>

     <appender name="Job1FileAppender" type="log4net.Appender.RollingFileAppender">
          <file type="log4net.Util.PatternString">
            <conversionPattern value="\Logs\Job1\Job1_Log_%date{yyyy.MM.dd.HH.mm.ss}-%processid.txt"/>
          </file>
          <filter type="log4net.Filter.LoggerMatchFilter">
            <loggerToMatch value="Job1"/>
          </filter>
          <filter type="log4net.Filter.DenyAllFilter"/>
          <appendToFile value="true"/>
          <rollingStyle value="Size"/>
          <maxSizeRollBackups value="10"/>
          <maximumFileSize value="25MB"/>
          <staticLogFileName value="true"/>
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
          </layout>
        </appender>
    <appender name="Job2FileAppender" type="log4net.Appender.RollingFileAppender">
              <file type="log4net.Util.PatternString">
                <conversionPattern value="\Logs\Job2\Job2_Log_%date{yyyy.MM.dd.HH.mm.ss}-%processid.txt"/>
              </file>
              <filter type="log4net.Filter.LoggerMatchFilter">
                <loggerToMatch value="Job2"/>
              </filter>
              <filter type="log4net.Filter.DenyAllFilter"/>
              <appendToFile value="true"/>
              <rollingStyle value="Size"/>
              <maxSizeRollBackups value="10"/>
              <maximumFileSize value="25MB"/>
              <staticLogFileName value="true"/>
              <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
              </layout>
            </appender>

<logger name="Job1" additivity="true">
      <level value="ALL" />
      <appender-ref ref="Job1FileAppender" />
    </logger>
    <logger name="Job2" additivity="true">
      <level value="ALL" />
      <appender-ref ref="Job2FileAppender" />
    </logger>
    </log4net>

Мне нужно записывать журналы Job1 и Job2 в соответствующий файл журнала, даже если все пять заданий выполняются одновременно. Любая помощь/предложения будут оценены!


person techV    schedule 17.02.2020    source источник
comment
Я бы проверил это stackoverflow.com/questions/51345161/ и посмотрите на CreateLogger(), чтобы убедиться, что он создан правильно, если я правильно понимаю, в противном случае вы просто получаете регистратор по умолчанию.   -  person Netferret    schedule 26.02.2020
comment
@Netferret, спасибо, проверим это. Для каждого задания есть отдельный файл класса, такой как ServiceJob1, который имеет правильный регистратор в функции GetLogger, как указано выше.   -  person techV    schedule 27.02.2020


Ответы (1)


Из вашего кода кажется, что вы можете передавать один и тот же LogManager.GetLogger("Job1") каждый раз из вашего JobFactory.

Я обычно делаю свой собственный JobFactory, который использует контейнер IoC внутри. Если бы мне пришлось передавать разные регистраторы для разных заданий, я бы просто настроил их в настройке контейнера IoC, и контейнер понял это для меня.

Если контейнер IoC не является тем, как вы создаете задания, вы можете ввести регистратор в метод NewJob, подобный этому

public class CustomJobFactory : IJobFactory
{
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        var newJob = // Create job somehow
        ((ILoggerEnabledJob)newJob).AppLogger = LogManager.GetLogger(bundle.JobDetail.JobType.Name);

        return newJob;
    }

    public void ReturnJob(IJob job)
    {
        // ...
    }
}

Другой вариант, который следует рассмотреть, — просто использовать статический регистратор в каждом задании.

person starteleport    schedule 26.02.2020
comment
спасибо за ваш ценный пост ... да, я уже создал фабрику пользовательских заданий, но забыл упомянуть в сообщении выше. Отредактировал свой пост сейчас... - person techV; 27.02.2020
comment
Код вашей фабрики говорит, что вы берете AppLogger из-за пределов фабричного класса. Мое предложение состоит в том, чтобы фабрика создала фактический экземпляр регистратора, как в моем фрагменте кода. bundle.JobDetail.JobType содержит System.Type создаваемого задания, и уже достаточно информации для создания регистратора. - person starteleport; 27.02.2020