Это будет длинный вопрос, но, пожалуйста, несите меня. Я пытаюсь создать компонент Logging для наших приложений, который может быть расширен для добавления новых фреймворков регистрации (NLog, Log4Net ec). Теперь я знаю, что у нас уже есть Common.Logging фасад, написанный Бен Фостером, но я хотел попробовать что-то более индивидуальное. Одним из основных требований в нашем случае является то, что нам нужен специальный механизм регистрации отдельных параметров/значений в базе данных с использованием структуры ведения журнала (в этом случае NLog). Таким образом, у меня есть простой интерфейс регистрации:Как получить имена журналов LogManager (NLog) с Unity
/// <summary>
/// Interface for implementing a Logger Provider.
/// </summary>
public interface ILogger
{
/// <summary>
/// Logs an Info level diagnostics message.
/// </summary>
/// <param name="logInfo">The Log Info object.</param>
void Info(LogInfo logInfo);
/// <summary>
/// Logs a Warn level diagnostics message.
/// </summary>
/// <param name="logInfo">The Log Info object.</param>
void Warn(LogInfo logInfo);
/// <summary>
/// Logs a Debug level diagnostics message.
/// </summary>
/// <param name="logInfo">The Log Info object.</param>
void Debug(LogInfo logInfo);
/// <summary>
/// Logs an Error level diagnostics message.
/// </summary>
/// <param name="logInfo">The Log Info object.</param>
void Error(LogInfo logInfo);
/// <summary>
/// Logs an Fatal level diagnostics message.
/// </summary>
/// <param name="logInfo">The Log Info object.</param>
void Fatal(LogInfo logInfo);
}
Объект LogInfo содержит всю необходимую информацию для ведения журнала. У меня есть абстрактный класс, который реализует интерфейс:
public abstract class NLogLoggerBase : ILogger
{
....
}
Который sublcassed в:
public class NLogDatabaseLogger : NLogLoggerBase
{
public NLogDatabaseLogger(ILogUtility logUtility)
: base(logUtility)
{
//Make sure the custom target is registered for use BEFORE using it.
ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(DatabaseLogTarget));
//initialize the _logger
_logger = LogManager.GetLogger("DatabaseLogger");
}
}
и
public class NLogFileLogger : NLogLoggerBase
{
....
}
базы данных регистратор использует пользовательский DatabaseTarget (который наследуется от TargetWithLayout в NLog) для входа в базу данных, а также для File Logger. Основные настройки для NLog подключены в App.Config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
</configSections>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true" throwExceptions="false" internalLogFile="C:\Temp\nlog.txt" internalLogLevel="Info"
internalLogToConsole="false">
<targets async="true">
<target name="CustomDatabaseLog" xsi:type="DatabaseLog" />
<target name="CustomFileLog" xsi:type="File" />
</targets>
<rules>
<logger name="DatabaseLogger" minlevel="Info" writeTo="CustomDatabaseLog" />
<logger name="FileLogger" minlevel="Info" writeTo="CustomFileLog" />
</rules>
</nlog>
</configuration>
Пока все хорошо. У меня есть несколько тестов для каждого из регистраторов, и они регистрируются в соответствии с их целевыми показателями.
Тогда я написал Logger завод, который будет возвращать правильное применение интерфейса ILogger, на основе типа регистратора:
/// <summary>
/// Provides an interface for a factory which returns a logger component.
/// </summary>
public interface ILoggerFactory
{
/// <summary>
/// Creates an instance of logger component based on dependency registration key.
/// </summary>
/// <param name="loggerName">The dependency registration key.</param>
/// <returns>An Instance of logger component.</returns>
ILogger CreateLogger(string loggerName);
}
и реализации:
/// <summary>
/// Implementation of ILoggerFactory interface.
/// </summary>
public class NLogLoggerFactory : ILoggerFactory
{
private readonly ILogger _nlogDatabaseLogger;
private readonly ILogger _nlogFileLogger;
public NLogLoggerFactory(ILogger nlogDatabaseLogger, ILogger nlogFileLogger)
{
if (nlogDatabaseLogger == null)
throw new ArgumentNullException("nlogDatabaseLogger");
if (nlogFileLogger == null)
throw new ArgumentNullException("nlogFileLogger");
_nlogDatabaseLogger = nlogDatabaseLogger;
_nlogFileLogger = nlogFileLogger;
}
/// <summary>
/// Creates an instance of logger component based on dependency registration key.
/// </summary>
/// <param name="loggerKey">The dependency registration key.</param>
/// <returns>An Instance of logger component.</returns>
public ILogger CreateLogger(string loggerKey)
{
if (loggerKey.Equals(DependencyRegistrationKeys.NLogDatabaseLoggerKey))
return _nlogDatabaseLogger;
if (loggerKey.Equals(DependencyRegistrationKeys.NLogFileLoggerKey))
return _nlogFileLogger;
throw new ArgumentException("Invalid loggerKey");
}
Так я иду к проводке все это с Единством. Вот быстрый тест я залетела (я знаю, что нужно рефакторинга, но для иллюстративных целей):
[Test]
public void Test_if_logger_factory_returns_correct_implementation()
{
var container = new UnityContainer();
container.RegisterType<ILogUtility, NLogUtility>();
container.RegisterType<ILogger, NLogDatabaseLogger>(DependencyRegistrationKeys.NLogDatabaseLoggerKey);
container.RegisterType<ILogger, NLogFileLogger>(DependencyRegistrationKeys.NLogFileLoggerKey);
container.RegisterType<ILoggerFactory, NLogLoggerFactory>(
new InjectionConstructor(
new ResolvedParameter<ILogger>(DependencyRegistrationKeys.NLogDatabaseLoggerKey),
new ResolvedParameter<ILogger>(DependencyRegistrationKeys.NLogFileLoggerKey)));
var loggerFactory = container.Resolve<ILoggerFactory>();
Assert.IsAssignableFrom<NLogLoggerFactory>(loggerFactory);
var logger = loggerFactory.CreateLogger(DependencyRegistrationKeys.NLogDatabaseLoggerKey);
Assert.IsNotNull(logger);
Assert.IsAssignableFrom<NLogDatabaseLogger>(logger);
}
Все хорошо, пока я не попал в линию:
var loggerFactory = container.Resolve<ILoggerFactory>();
Это кажется ударить конструктор NLogDatabaseLogger, как и ожидалось, и взрывается на этой линии с исключением:
//initialize the _logger
_logger = LogManager.GetLogger("DatabaseLogger");
исключение:
Required parameter 'FileName' on 'File Target[CustomFileLog_wrapped]' was not specified.
Я предполагаю, что Unity борется с получением NLog, чтобы получить именованный экземпляр журнала. кто-нибудь сталкивался с этим раньше? Это что-то в этом роде? Я потратил все это время, стукнув головой об этом, но без кубиков. Любая помощь могла бы быть полезна!
Где код для LogManager? Это от NLog? Я не думаю, что Unity является проблемой здесь, поскольку LogManager.GetLogger выглядит как вызов статического метода, NLogLoggerBase будет там, где нарушительный код находится в I reckon –
True, LogManager - это статический класс, открытый NLog. Я закончил перемещение кода FileTarget в файл app.config – tranceporter