ネットワーク上のワークステーションの正常性をチェックし、見つかった問題に応じて修正するツールを作成しています。アプリが各マシンでタスク/チェックを実行しているときに、ログファイルを作成したいと思います。今のところ、これを1台のマシンで動作させたいだけなのですが、やがて、100台以上のマシンを一度にスキャンすることになります(スレッド化)。
ログファイルを作成する最良の方法は何ですか?
私はList<string>
メモリ内にログファイルを作成し、終了したらファイルに出力します。
私はこれを行うより良い方法があるかもしれないと思っていますか?
サードパーティのライブラリを使用せず、xmlファイルにログを記録します。
これは、異なるスレッドからxmlファイルへのロギングを行うコードサンプルです。
private static readonly object Locker = new object();
private static XmlDocument _doc = new XmlDocument();
static void Main(string[] args)
{
if (File.Exists("logs.txt"))
_doc.Load("logs.txt");
else
{
var root = _doc.CreateElement("hosts");
_doc.AppendChild(root);
}
for (int i = 0; i < 100; i++)
{
new Thread(new ThreadStart(DoSomeWork)).Start();
}
}
static void DoSomeWork()
{
/*
* Here you will build log messages
*/
Log("192.168.1.15", "alive");
}
static void Log(string hostname, string state)
{
lock (Locker)
{
var el = (XmlElement)_doc.DocumentElement.AppendChild(_doc.CreateElement("Host"));
el.SetAttribute("Hostname", hostname);
el.AppendChild(_doc.CreateElement("State")).InnerText = state;
_doc.Save("logs.txt");
}
}
log4net をお勧めします。
複数のログファイルが必要になります。したがって、複数のファイルアペンダー。さらに、ファイルアペンダーを動的に作成できます。
サンプルコード:
using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
// Set the level for a named logger
public static void SetLevel(string loggerName, string levelName)
{
ILog log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.Level = l.Hierarchy.LevelMap[levelName];
}
// Add an appender to a logger
public static void AddAppender(string loggerName, IAppender appender)
{
ILog log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.AddAppender(appender);
}
// Create a new file appender
public static IAppender CreateFileAppender(string name, string fileName)
{
FileAppender appender = new
FileAppender();
appender.Name = name;
appender.File = fileName;
appender.AppendToFile = true;
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
return appender;
}
// In order to set the level for a logger and add an appender reference you
// can then use the following calls:
SetLevel("Log4net.MainForm", "ALL");
AddAppender("Log4net.MainForm", CreateFileAppender("appenderName", "fileName.log"));
// repeat as desired
ソース/良いリンク:
Log4Net:プログラムで複数のロガーを指定します(複数のファイルアペンダーを使用)
log4netをゼロからプログラムで設定する方法(設定なし)
さらに、log4netではイベントログへの書き込みも可能です。すべてが構成ベースであり、構成は実行時にxmlから動的にロードすることもできます。
編集2:
その場でログファイルを切り替える1つの方法:Log4Net構成ファイルは環境変数をサポートします。
Environment.SetEnvironmentVariable("log4netFileName", "MyApp.log");
そして、log4net config:
<param name="File" value="${log4netFileName}".log/>
ロギングについて多くの調査を行い、NLogが最適なものであると判断しました。
http://nlog-project.org/ を参照してください
log4net vs. Nlog および http://www.dotnetlogging.com/comparison/ も参照してください
イベントログを使用することもできます。 C#からアクセスする方法は次のとおりです http://support.Microsoft.com/kb/307024/en
しかし、使用する方法が何であれ、プロセスが終了するときではなく、ログに何かが追加されるたびにファイルに出力することをお勧めします。これにより、クラッシュやプロセスの場合にデータが失われることはありません殺される。
Nlog http://nlog-project.org/ を使用します。無料で、ファイル、データベース、イベントログ、および他の20以上のターゲットに書き込むことができます。もう1つのロギングフレームワークはlog4net- http://logging.Apache.org/log4net/ (Java Log4jプロジェクトから移植)。無料です。
ベストプラクティスは、一般的なロギングを使用することです。 http://commons.Apache.org/logging/ したがって、後でNLogまたはlog4netを他のロギングフレームワークに変更できます。
Apache log4net library を使用できます。
using System;
using log4net;
using log4net.Config;
public class MyApp
{
// Define a static logger variable so that it references the
// Logger instance named "MyApp".
private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
static void Main(string[] args)
{
XmlConfigurator.Configure(new System.IO.FileInfo(@"..\..\resources\log4net.config"));
log.Info("Entering application.");
Console.WriteLine("starting.........");
log.Info("Entering application.");
log.Error("Exiting application.");
Console.WriteLine("starting.........");
}
}
この設定ファイルを追加します
*************************************************************************************
<!--Configuration for file appender-->
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="logfile.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p [%logger] - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
</configuration>
*************************************************************************************
<!--Configuration for console appender-->
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,
log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p [%logger] - %m%n" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
</configuration>
組み込みの.NETトレース機能もご覧ください。ログファイルに出力できるトレースリスナのセットがありますが、イベントビューアまたはデータベース(またはそれらすべてに同時に)にログインするように構成できます。
http://www.codeguru.com/csharp/.net/net_debugging/tracing/article.php/c5919/NET-Tracing-Tutorial.htm
http://logging.Apache.org/ libraryを使用し、データベースアペンダーを使用してすべてのログ情報をまとめて収集できます。
スレッドセーフ--staticクラスを使用しています。主なアイデアは、リストのメッセージをキューに入れてから、各期間または各カウンター制限ごとにログファイルに保存することです。
重要:プログラムを終了するときは、保存ファイル(DirectLog.SaveToFile();
)を強制する必要があります。 (リストにまだいくつかの項目がある場合)
使用は非常に簡単です:DirectLog.Log("MyLogMessage", 5);
これは私のコードです:
using System;
using System.IO;
using System.Collections.Generic;
namespace Mendi
{
/// <summary>
/// class used for logging misc information to log file
/// written by Mendi Barel
/// </summary>
static class DirectLog
{
readonly static int SAVE_PERIOD = 10 * 1000;// period=10 seconds
readonly static int SAVE_COUNTER = 1000;// save after 1000 messages
readonly static int MIN_IMPORTANCE = 0;// log only messages with importance value >=MIN_IMPORTANCE
readonly static string DIR_LOG_FILES = @"z:\MyFolder\";
static string _filename = DIR_LOG_FILES + @"Log." + DateTime.Now.ToString("yyMMdd.HHmm") + @".txt";
readonly static List<string> _list_log = new List<string>();
readonly static object _locker = new object();
static int _counter = 0;
static DateTime _last_save = DateTime.Now;
public static void NewFile()
{//new file is created because filename changed
SaveToFile();
lock (_locker)
{
_filename = DIR_LOG_FILES + @"Log." + DateTime.Now.ToString("yyMMdd.HHmm") + @".txt";
_counter = 0;
}
}
public static void Log(string LogMessage, int Importance)
{
if (Importance < MIN_IMPORTANCE) return;
lock (_locker)
{
_list_log.Add(String.Format("{0:HH:mm:ss.ffff},{1},{2}", DateTime.Now, LogMessage, Importance));
_counter++;
}
TimeSpan timeDiff = DateTime.Now - _last_save;
if (_counter > SAVE_COUNTER || timeDiff.TotalMilliseconds > SAVE_PERIOD)
SaveToFile();
}
public static void SaveToFile()
{
lock (_locker)
if (_list_log.Count == 0)
{
_last_save = _last_save = DateTime.Now;
return;
}
lock (_locker)
{
using (StreamWriter logfile = File.AppendText(_filename))
{
foreach (string s in _list_log) logfile.WriteLine(s);
logfile.Flush();
logfile.Close();
}
_list_log.Clear();
_counter = 0;
_last_save = DateTime.Now;
}
}
public static void ReadLog(string logfile)
{
using (StreamReader r = File.OpenText(logfile))
{
string line;
while ((line = r.ReadLine()) != null)
{
Console.WriteLine(line);
}
r.Close();
}
}
}
}
GitHubで heiswayi から SimpleLogger を見つけました。