2012-04-20 22 views
30

Estoy escribiendo una herramienta que va a verificar el estado de las estaciones de trabajo en una red, y lo arreglaré de acuerdo con los problemas que encuentre. Quiero crear un archivo de registro a medida que la aplicación se ejecuta a través de sus tareas/verificaciones en cada máquina. Solo quiero que esto funcione en una sola máquina por el momento, pero con el tiempo escaneará más de 100 máquinas de una vez (Enhebrado).C# Mejor método para crear un archivo de registro

¿Cuál es la mejor manera de crear un archivo de registro?

Yo estaba pensando en usar un List<string> para construir el archivo de registro en la memoria y luego la salida a un archivo una vez que había terminado.

Solo estoy pensando que puede haber una forma mejor de hacer esto?

+0

Estoy interesado también –

+1

¿Hay una sola aplicación en ejecución que escanee todas las máquinas de forma remota o su aplicación se implementará en cada máquina individualmente? –

+0

¿desea crear un archivo de registro o por máquina? – Reniuz

Respuesta

7

No utilizaría bibliotecas de terceros, me gustaría iniciar sesión en un archivo xml.

Este es un ejemplo de código que el registro en un archivo XML desde diferentes hilos:

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"); 
     } 
    } 
+0

Normalmente no estoy de acuerdo y digo usar log4net o Enterprise Library ... por qué reinventar la rueda. Pero esta solución es simple y adecuada para la situación, y si no ha utilizado esas soluciones antes, probablemente sea más rápido que leer los documentos y configurarlos. ¡Bien hecho! –

+2

-1 - No soy experto en .Net pero parece que está guardando todo el archivo de registro en el disco para cada llamada a 'Log (string, string)', no solo que está manteniendo una copia del archivo de registro en memoria en '_doc' que seguramente no es una buena idea. –

+3

Gareth, si se produce un bloqueo en la aplicación, el proceso se cancela, o la computadora se reinicia y los registros no se guardan para cada llamada, entonces realmente estamos en problemas. Acerca de la memoria, creo que costará mucha más memoria cargar documentos xml para cada llamada de Log (string, string) (piense en 100 hilos). – croisharp

5

¡Es posible que desee utilizar el registro de eventos! Aquí es cómo acceder a él desde C# http://support.microsoft.com/kb/307024/en

Pero cualquiera que sea el método que va a utilizar, lo recomiendo a la salida a un archivo cada vez que algo se añade al registro y no cuando sus salidas de proceso, lo que ganó No pierdas datos en caso de falla o si tu proceso es asesinado.

2

Puede usar la biblioteca http://logging.apache.org/ y usar un appender de base de datos para recopilar toda su información de registro.

5

Uso del Nlog http://nlog-project.org/. Es gratis y permite escribir en un archivo, base de datos, registro de eventos y otros objetivos de más de 20 años. El otro marco de registro es log4net - http://logging.apache.org/log4net/ (portado desde el proyecto java Log4j). También es gratis.

Las mejores prácticas son utilizar el registro común: http://commons.apache.org/logging/ para poder cambiar posteriormente NLog o log4net a otro marco de trabajo de registro.

11

recomendaría log4net.

Necesitará varios archivos de registro. Así que múltiples appenders de archivos. Además, puedes crear los appenders de archivos dinámicamente.

Código de ejemplo:

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 

Fuentes/Buenas conexiones:

Log4Net: Programmatically specify multiple loggers (with multiple file appenders)

Adding appenders programmatically

How to configure log4net programmatically from scratch (no config)

Plus, el log4net también permite escribir en el registro de eventos también. Todo se basa en la configuración, y la configuración también puede cargarse dinámicamente desde xml en el tiempo de ejecución.

Edición 2:

Una forma de cambiar los archivos de registro sobre la marcha: fichero de configuración Log4net soporta variables de entorno:

Environment.SetEnvironmentVariable("log4netFileName", "MyApp.log"); 

y en la configuración de log4net:

<param name="File" value="${log4netFileName}".log/> 
+0

Muchas gracias por esto, muy apreciado. – Derek

4

podría utilizar el 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........."); 
    } 
} 
4

agregar este archivo de configuración


************************************************************************************* 
<!--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> 
1

Estoy usando hilo seguro estática clase. La idea principal es poner en cola el mensaje en la lista y luego guardarlo en el archivo de registro cada período de tiempo, o cada límite del contador.

Importante: debe forzar guardar el archivo (DirectLog.SaveToFile();) cuando salga del programa. (En caso de que todavía hay algunos elementos de la lista)

El uso es muy sencillo: DirectLog.Log("MyLogMessage", 5);

Este es mi código:

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(); 
      } 
     } 
    } 
} 
+0

No es necesario bloquear un archivo. Thread.Sleep (1)! Asegúrate de que no puedes abrir el archivo para escribir. El archivo será tu bloqueo. Este es un hilo, proceso, aplicación, servidor, ... seguro. El bloqueo de un objeto solo es seguro para el proceso. – TamusJRoyce

Cuestiones relacionadas