我有一个已经使用NLog的项目。应用程序创建给定类的实例将ILogger的实例传递给它,然后调用" execute"实例中的方法 - 系统是多线程的,一次可以运行多达200个这样的实例,日志文件可能变得很大而且难以阅读。
我们需要为每个类的实例创建一个新的日志文件,并将其与该实例的输出一起存储(它们每个都有唯一的标识符)
我的问题是:NLog是否可以为每个类的实例创建一个新文件?我知道你可以为不同的类提供不同的日志文件,我想要的是每个类实例的不同日志文件。
我已经在网上查了但是无法找到关于此的更多信息,我不想通过创建我自己的日志记录类来重新发明轮子,如果它已经在NLog中提供了。
下面是一个控制台应用程序,我已经敲了一下来演示重新配置现有记录器时会发生什么 - 实际上它会更改记录器的所有实例
class Program
{
static void Main(string[] args)
{
BackgroundWorker bw1 = new BackgroundWorker();
bw1.DoWork += Bw1_DoWork;
bw1.RunWorkerAsync();
BackgroundWorker bw2 = new BackgroundWorker();
bw2.DoWork += Bw2_DoWork;
bw2.RunWorkerAsync();
Console.ReadLine();
}
private static void Bw1_DoWork(object sender, DoWorkEventArgs e)
{
workLoad one = new workLoad("One");
one.execute();
}
private static void Bw2_DoWork(object sender, DoWorkEventArgs e)
{
workLoad one = new workLoad("Two");
one.execute();
}
}
public class workLoad
{
private ILogger _logger { get; set; }
private string _number { get; set; }
public workLoad(string number)
{
_logger = LogManager.GetCurrentClassLogger();
_number = number;
var target = (FileTarget) LogManager.Configuration.FindTargetByName("DebugFile");
target.FileName = $"c:\\temp\\File{number}.txt";
LogManager.ReconfigExistingLoggers();
}
public void execute()
{
for (int i = 0; i < 1000; i++)
{
_logger.Info(_number + " LOOPING" + i);
}
}
}
这导致所有输出转到一个文件(two.txt),日志文件的样本在下面。
2017-06-13 17:00:42.4156 TestNlog.workLoad两个LOOPING0 2017-06-13 17:00:42.4156 TestNlog.workLoad一个LOOPING0 2017-06-13 17:00:42.4806 TestNlog.workLoad一个LOOPING1 2017-06-13 17:00:42.4746 TestNlog.workLoad两个LOOPING1 2017-06-13 17:00:42.4806 TestNlog.workLoad一个LOOPING2 2017-06-13 17:00:42.4806 TestNlog.workLoad两个LOOPING2 2017-06-13 17:00:42.4946 TestNlog.workLoad One LOOPING3 2017-06-13 17:00:42.4946 TestNlog.workLoad两个LOOPING3 2017-06-13 17:00:42.4946 TestNlog.workLoad One LOOPING4 2017-06-13 17:00:42.4946 TestNlog.workLoad两个LOOPING4 2017-06-13 17:00:42.5132 TestNlog.workLoad One LOOPING5 2017-06-13 17:00:42.5132 TestNlog.workLoad两个LOOPING5 2017-06-13 17:00:42.5132 TestNlog.workLoad One LOOPING6 2017-06-13 17:00:42.5257 TestNlog.workLoad两个LOOPING6 2017-06-13 17:00:42.5257 TestNlog.workLoad One LOOPING7 2017-06-13 17:00:42.5257 TestNlog.workLoad两个LOOPING7 2017-06-13 17:00:42.5407 TestNlog.workLoad两个LOOPING8 2017-06-13 17:00:42.5407 TestNlog.workLoad One LOOPING8 2017-06-13 17:00:42.5407 TestNlog.workLoad两个LOOPING9 2017-06-13 17:00:42.5407 TestNlog.workLoad One LOOPING9 2017-06-13 17:00:42.5577 TestNlog.workLoad两个LOOPING10 2017-06-13 17:00:42.5577 TestNlog.workLoad One LOOPING10
理想情况下,我正在寻找从实例1到One.TXT的所有内容以及从实例2到2.txt的所有内容(你可以看到200+这样的运行可能是个问题!)
答案 0 :(得分:3)
也许尝试在fileName中使用<targets>
<target xsi:type="File" name="DebugFile"
fileName="${basedir}\logs\${logger:shortName=true}.txt" />
</targets>
(NLog文件存档逻辑需要NLog 4.5才能正常工作):
_logger = LogManager.GetCurrentClassLogger();
然后文件名将与logger-name匹配。创建记录器时,不要这样做:
_logger = LogManager.GetCurrentClassLogger(typeof(workLoad).ToString() + "." + number);
然后这样做:
private static object _lock = new object();
public static NLog.Logger PrepareLogger(string number)
{
lock (_lock)
{
var fileTarget = LogManager.Configuration.FindTargetByName(number);
if (fileTarget == null)
{
var fileTarget = new FileTarget(number);
fileTarget.FileName = $"c:\\temp\\File{number}.txt";
var template = LogManager.Configuration.FindTargetByName("DebugFile");
if (template != null)
{
fileTarget.Layout = template.Layout;
}
LogManager.Configuration.AddTarget(fileTarget);
var rule = new LoggingRule(number, LogLevel.Debug, fileTarget) { Final = true };
LogManager.Configuration.LoggingRules.Add(rule);
LogManager.ReconfigExistingLoggers();
}
}
return LogManager.GetLogger(number);
}
另外你可以像这样创建Loggers(如果有效则不测试):
struct SubFormArgs{};
struct OtherSubFormArgs{
OtherSubFormArgs(std::string s) : param1(s){}
std::string param1;
};
struct Form{};
struct SubForm : Form{
SubForm(SubFormArgs){}
};
struct OtherSubForm : Form{
OtherSubForm(OtherSubFormArgs args): myStr(args.param1){}
std::string myStr;
}
答案 1 :(得分:0)
也许你可以让类的构造函数初始化一个新的日志
答案 2 :(得分:0)
尝试ReconfigExistingLoggers
,可能是您最好的选择。
<targets>
<target xsi:type="File"
name="Foo"
fileName="${basedir}/logs/logfile.txt"
keepFileOpen="false"
encoding="iso-8859-2" />
</targets>
然后
var target = (FileTarget)LogManager.Configuration.FindTargetByName("Foo");
target.FileName = $"{change_my_location}/class_instance.txt";
LogManager.ReconfigExistingLoggers();
答案 3 :(得分:0)
您可以在运行时创建自己的目标,也可以在布局中添加参数并将其传递给它。
创建自定义日志文件
/// <summary>
/// Creates the custom log file.
/// Logging of Info and Warning Message Only.
/// </summary>
/// <param name="TargetName">Name of the target.</param>
/// <param name="TargetFileName">Name of the target file.</param>
/// <param name="LoggerName">Name of the logger.</param>
public void CreateCustomLogFile(String TargetName, String TargetFileName, String LoggerName = "*")
{
try
{
var NLogTarget = LogManager.Configuration.FindTargetByName(TargetName);
if (NLogTarget == null) //Don't Re Add the Target
{
NLogTarget = new FileTarget()
{
Name = TargetName,
FileName = TargetFileName,
Layout = @"[${date:format=yyyy-MM-dd HH\:mm\:ss}] ${message}"
};
LogManager.Configuration.AddTarget(TargetName, NLogTarget);
}
var NLogRule = new LoggingRule(LoggerName, NLogTarget);
NLogRule.EnableLoggingForLevel(LogLevel.Info);
NLogRule.EnableLoggingForLevel(LogLevel.Warn);
LogManager.Configuration.LoggingRules.Add(NLogRule);
LogManager.ReconfigExistingLoggers();
}
catch { }
}
/// <summary>
/// Removes the custom log file.
/// </summary>
/// <param name="TargetName">Name of the target.</param>
public void RemoveCustomLogFile(String TargetName)
{
try
{
if (LogManager.Configuration.FindTargetByName(TargetName) != null)
{
var Target = LogManager.Configuration.FindTargetByName(TargetName);
foreach (var rule in LogManager.Configuration.LoggingRules)
{
rule.Targets.Remove(Target);
}
LogManager.Configuration.RemoveTarget(TargetName);
Target.Dispose();
LogManager.ReconfigExistingLoggers();
}
}
catch { }
}
或将参数添加到NLog布局
<target name="CTSCoreByPortNumber" xsi:type="File"
fileName="${logDirectory}/CTS${event-context:item=PortNumber}.log"
layout="${fulllayout}" />
写入正确日志的示例函数。
/// <summary>
/// WriteLog - Overloaded Method to write a Message.
/// </summary>
/// <param name="LogType">LogLevel.Trace
/// LogLevel.Debug,
/// LogLevel.Info,
/// LogLevel.Warn,
/// LogLevel.Error,
/// LogLevel.Fatal,</param>
/// <param name="Msg">Message to write</param>
/// <param name="args">Arguments</param>
public void WriteLog(LogLevel LogType, String Msg, object[] args)
{
try
{
if (args == null)
args = new object[0];
LogEventInfo logEvent = new LogEventInfo(LogType, GetCallingMethodName(), null, String.Format(Msg, args), null);
if (PortNumber != 0)
logEvent.Properties["PortNumber"] = ".Line_" + PortNumber;
Instance.Log(typeof(Logging), logEvent);
//Instance.Log((LogLevel)LogType, Msg, args);
}
catch (Exception) { throw; }
}
目标中的PortNumber由日志记录之前的属性代码设置。