Ich schreibe ein Tool, das den Zustand von Workstations in einem Netzwerk überprüft und je nach den gefundenen Problemen korrigiert. Ich möchte eine Protokolldatei erstellen, während die App ihre Aufgaben/Prüfungen auf jedem Rechner ausführt. Ich möchte, dass dies für einen Moment auf einer einzigen Maschine funktioniert, aber mit der Zeit werden 100+ Maschinen in einem Durchgang gescannt (Threaded out).
Wie lässt sich eine Protokolldatei am besten erstellen?
Ich dachte daran, einen List<string>
zu verwenden, um die Protokolldatei im Speicher aufzubauen und sie anschließend in eine Datei auszugeben, sobald sie fertig war.
Ich denke nur, dass es einen besseren Weg gibt, dies zu tun?
Ich würde keine Bibliotheken von Drittanbietern verwenden, ich würde mich in eine XML-Datei einloggen.
Dies ist ein Codebeispiel, in dem von verschiedenen Threads aus eine XML-Datei protokolliert wird:
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");
}
}
Ich würde log4net empfehlen.
Sie benötigen mehrere Protokolldateien. Also mehrere Datei-Appenders. Außerdem können Sie die Datei-Appenders dynamisch erstellen.
Beispielcode:
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
Quellen/gute Links:
Log4Net: Programmgesteuert mehrere Logger angeben (mit mehreren Datei-Appendern)
Appender programmgesteuert hinzufügen
Wie programmiere ich log4net von Grund auf neu (keine Konfiguration)
Außerdem können Sie mit log4net auch in das Ereignisprotokoll schreiben. Alles ist konfigurationsbasiert und die Konfiguration kann zur Laufzeit auch dynamisch aus xml geladen werden.
Edit 2:
Eine Möglichkeit, die Protokolldateien schnell zu wechseln: Die Log4Net-Konfigurationsdatei unterstützt Umgebungsvariablen:
Environment.SetEnvironmentVariable("log4netFileName", "MyApp.log");
und in der log4net config:
<param name="File" value="${log4netFileName}".log/>
Wir haben viel über das Logging geforscht und entschieden, dass NLog das Beste ist.
Siehe http://nlog-project.org/
Siehe auch log4net vs. Nlog Und http://www.dotnetlogging.com/comparison/
Möglicherweise möchten Sie das Ereignisprotokoll verwenden! So greifen Sie unter C # http://support.Microsoft.com/kb/307024/de darauf zu.
Was auch immer die Methode ist, die Sie verwenden möchten. Ich würde empfehlen, jedes Mal eine Datei auszugeben, wenn etwas an das Protokoll angehängt wird, und nicht, wenn Ihr Prozess beendet ist, damit Sie bei einem Absturz oder bei einem Prozess keine Daten verlieren wurde getötet.
Verwenden Sie das Nlog http://nlog-project.org/ . Es ist kostenlos und ermöglicht das Schreiben in Dateien, Datenbanken, Ereignisprotokolle und andere 20+ Ziele. Das andere Protokollierungs-Framework ist log4net - http://logging.Apache.org/log4net/ (von Java portiert) Log4j-Projekt). Es ist auch kostenlos.
Bewährte Methoden sind die Verwendung der allgemeinen Protokollierung - http://commons.Apache.org/logging/ Sie können später NLog oder log4net in ein anderes Protokollierungs-Framework ändern.
Sie können die Bibliothek Apache log4net verwenden :
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.........");
}
}
fügen Sie diese Konfigurationsdatei hinzu
*************************************************************************************
<!--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>
Sie können sich auch die integrierten .NET-Ablaufverfolgungsfunktionen ansehen. Es gibt eine Reihe von Ablaufverfolgungslistenern, die die Ausgabe in eine Protokolldatei ermöglichen. Sie können sie jedoch so konfigurieren, dass sie sich bei der Ereignisanzeige oder bei einer Datenbank (oder allen gleichzeitig) anmeldet.
http://www.codeguru.com/csharp/.net/net_debugging/tracing/article.php/c5919/NET-Tracing-Tutorial.htm
Sie können http://logging.Apache.org/ library verwenden und einen Datenbank-Appender verwenden, um alle Ihre Protokollinformationen zusammen zu sammeln.
Ich verwende threadsicher static class. Die Hauptidee besteht darin, die Nachricht in die Warteschlange zu stellen und dann für jeden Zeitraum oder jedes Zählerlimit in der Protokolldatei zu speichern.
Wichtig: Beim Beenden des Programms sollten Sie die Sicherungsdatei (DirectLog.SaveToFile();
) erzwingen. (falls noch einige Artikel auf der Liste stehen)
Die Verwendung ist sehr einfach: DirectLog.Log("MyLogMessage", 5);
Das ist mein Code:
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();
}
}
}
}
Ich fand das SimpleLogger from heiswayi auf GitHub gut.