c# - generate - Forma simple de realizar el registro de errores?
params comments c# (8)
Creé una pequeña aplicación C # winforms, como una característica adicional que estaba considerando agregar algún tipo de error al iniciar sesión en ella. ¿Alguien tiene alguna sugerencia de buenas maneras de hacer esto? Esta es una función que nunca he buscado agregar a proyectos anteriores, por lo que estoy abierto a sugerencias de Desarrolladores que tengan más experiencia.
Estaba considerando algo así como escribir excepciones a un archivo de texto específico, o posiblemente una tabla de base de datos. Esta es una aplicación que estará en uso durante unos meses y luego se descartará cuando termine un producto más grande.
Bueno, log4net funciona como un ladrillo. Puede ser un poco difícil de configurar, pero vale la pena. También le permite configurar el bloqueo de archivos de esos archivos de registro, etc.
Crear una clase llamada Log.cs Estoy utilizando Linq To SQl para guardar en la base de datos
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
public static partial class Log
{
/// <summary>
/// Saves the exception details to ErrorLogging db with Low Priority
/// </summary>
/// <param name="ex">The exception.</param>
public static void Save(this Exception ex)
{
Save(ex, ImpactLevel.Low, "");
}
/// <summary>
/// Saves the exception details to ErrorLogging db with specified ImpactLevel
/// </summary>
/// <param name="ex">The exception.</param>
/// <param name="impactLevel">The Impact level.</param>
public static void Save(this Exception ex, ImpactLevel impactLevel)
{
Save(ex, impactLevel,"");
}
/// <summary>
/// Saves the exception details to ErrorLogging db with specified ImpactLevel and user message
/// </summary>
/// <param name="ex">The exception</param>
/// <param name="impactLevel">The impact level.</param>
/// <param name="errorDescription">The error Description.</param>
public static void Save(this Exception ex, ImpactLevel impactLevel, string errorDescription)
{
using (var db = new ErrorLoggingDataContext())
{
Log log = new Log();
if (errorDescription != null && errorDescription != "")
{
log.ErrorShortDescription = errorDescription;
}
log.ExceptionType = ex.GetType().FullName;
var stackTrace = new StackTrace(ex, true);
var allFrames = stackTrace.GetFrames().ToList();
foreach (var frame in allFrames)
{
log.FileName = frame.GetFileName();
log.LineNumber = frame.GetFileLineNumber();
var method = frame.GetMethod();
log.MethodName = method.Name;
log.ClassName = frame.GetMethod().DeclaringType.ToString();
}
log.ImpactLevel = impactLevel.ToString();
try
{
log.ApplicationName = Assembly.GetCallingAssembly().GetName().Name;
}
catch
{
log.ApplicationName = "";
}
log.ErrorMessage = ex.Message;
log.StackTrace = ex.StackTrace;
if (ex.InnerException != null)
{
log.InnerException = ex.InnerException.ToString();
log.InnerExceptionMessage = ex.InnerException.Message;
}
log.IpAddress = ""; //get the ip address
if (System.Diagnostics.Debugger.IsAttached)
{
log.IsProduction = false;
}
try
{
db.Logs.InsertOnSubmit(log);
db.SubmitChanges();
}
catch (Exception eex)
{
}
}
}
}
Crea la siguiente tabla
USE [database Name]
GO
/****** Object: Table [dbo].[Log] Script Date: 9/27/2016 11:52:32 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Log](
[LogId] [INT] IDENTITY(1,1) NOT NULL,
[ErrorDate] [DATETIME] NOT NULL CONSTRAINT [DF_Log_Date] DEFAULT (GETDATE()),
[ErrorShortDescription] [VARCHAR](1000) NULL,
[ExceptionType] [VARCHAR](255) NULL,
[FileName] [VARCHAR](1000) NULL,
[LineNumber] [INT] NULL,
[MethodName] [VARCHAR](255) NULL,
[ClassName] [VARCHAR](150) NULL,
[ImpactLevel] [VARCHAR](50) NOT NULL,
[ApplicationName] [VARCHAR](255) NULL,
[ErrorMessage] [VARCHAR](4000) NULL,
[StackTrace] [VARCHAR](MAX) NULL,
[InnerException] [VARCHAR](2000) NULL,
[InnerExceptionMessage] [VARCHAR](2000) NULL,
[IpAddress] [VARCHAR](150) NULL,
[IsProduction] [BIT] NOT NULL CONSTRAINT [DF_Log_IsProduction] DEFAULT ((1)),
[LastModified] [DATETIME] NOT NULL CONSTRAINT [DF_Log_LastModified] DEFAULT (GETDATE()),
CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED
(
[LogId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
EXEC sys.sp_addextendedproperty @name=N''MS_Description'', @value=N''This table holds all the exceptions.
ErrorData = when error happened
,[ErrorShortDescription] == short desc about the error entered by the developers
,[FileName] = file where error happened full path
,[LineNumber] = line number where code failed
,[MethodName] = method name where exception happened
,[ClassName] = class where exception happened
,[ImpactLevel] = high, medium, low
,[ApplicationName] = name of the application where error came from
,[ErrorMessage] = exception error messge
,[StackTrace] = C# stack trace
,[InnerException] = inner exception of strack trace
,[InnerExceptionMessage] = inner message
,[IpAddress]
,[IsProduction]'' , @level0type=N''SCHEMA'',@level0name=N''dbo'', @level1type=N''TABLE'',@level1name=N''Log''
GO
El nivel de impacto es básicamente Enum
public enum ImpactLevel
{
High = 0,
Medium = 1,
Low = 2,
}
Puedes usarlo como sigue
try
{
}
catch(Exception ex)
{
//this will save the exception details and mark exception as low priority
ex.Save();
}
try
{
}
catch(Exception ex)
{
//this will save the exception details with priority you define: High, Medium,Low
ex.Save(ImpactLevel.Medium);
}
try
{
}
catch(Exception ex)
{
//this will save the exception details with priority you define: High, Medium,Low
ex.Save(ImpactLevel.Medium, "You can enter an details you want here ");
}
Después de leer las sugerencias aquí, terminé usando lo siguiente:
private void LogSystemError(string message)
{
EventLog.WriteEntry("YourAppName", message, EventLogEntryType.Error);
}
La clase EventLog está disponible usando System.Diagnostics.
Evité las opciones de iniciar sesión en archivos (por ejemplo, "yourLogFile.txt") para evitar problemas de concurrencia de múltiples hilos de errores de registro, ubicación del archivo y seguridad de acceso, y los posibles problemas de tener un archivo que crece demasiado.
Ejemplo de Heres para log4net:
- Cree un nuevo proyecto de consola llamado Log4NetTest
- Agregue el paquete log4net [1.2.13] nuget al proyecto
Escriba el siguiente programa:
using System.Threading.Tasks; using log4net; using System.Text; using System.CollectionsGeneric; using System; namespace Log4NetTest { class Program { private static readonly ILog _logger = LogManager.GetLogger("testApp.LoggingExample"); static void Main(string[] args) { // Configure from App.config. This is marked as obsolete so you can also add config into separate config file // and use log4net.Config.XmlConfigurator method to configure from xml file. log4net.Config.DOMConfigurator.Configure(); _logger.Debug("Shows only at debug"); _logger.Warn("Shows only at warn"); _logger.Error("Shows only at error"); Console.ReadKey(); } } }
Cambia tu app.config por la siguiente:
<!-- language: xml --> <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <log4net debug="false"> <appender name="LogFileAppender" type="log4net.Appender.FileAppender,log4net" > <param name="File" value="myLog.log" /> <param name="AppendToFile" value="true" /> <layout type="log4net.Layout.PatternLayout,log4net"> <param name="ConversionPattern" value="%date [%thread] %-5level %logger %ndc - %message%newline" /> </layout> </appender> <root> <priority value="ALL" /> <appender-ref ref="LogFileAppender" /> </root> <category name="testApp.LoggingExample"> <priority value="ALL" /> </category> </log4net> </configuration>
5. Ejecuta la aplicación y deberás encontrar el siguiente archivo de la carpeta bin / Debug:
2013-12-13 13:27:27,252 [8] DEBUG testApp.LoggingExample (null) - Shows only at debug
2013-12-13 13:27:27,280 [8] WARN testApp.LoggingExample (null) - Shows only at warn
2013-12-13 13:27:27,282 [8] ERROR testApp.LoggingExample (null) - Shows only at error
No excavaría demasiado en bibliotecas externas ya que sus necesidades de registro son simples.
.NET Framework ya incluye esta característica en el espacio de nombres System.Diagnostics, puede escribir todo el registro que necesita allí simplemente llamando a los métodos en la clase Trace :
Trace.TraceInformation("Your Information");
Trace.TraceError("Your Error");
Trace.TraceWarning("Your Warning");
Y luego configure todos los detectores de rastreo que se ajusten a sus necesidades en su archivo app.config:
<configuration>
// other config
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="consoleListener" type="System.Diagnostics.ConsoleTraceListener"/>
<add name="textWriterListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="YourLogFile.txt"/>
<add name="eventLogListener" type="System.Diagnostics.EventLogTraceListener" initializeData="YourEventLogSource" />
<remove name="Default"/>
</listeners>
</trace>
</system.diagnostics>
// other config
</configuration>
o si lo prefiere, también puede configurar sus oyentes en su aplicación, sin depender de un archivo de configuración:
Trace.Listeners.Add(new TextWriterTraceListener("MyTextFile.log"));
Recuerde establecer la propiedad Trace.AutoFlush en verdadero, para que el registro de texto funcione correctamente.
Puedes usar SimpleLog .
Es una solución de registro simple, robusta y poderosa de una sola clase, fácil de entender, fácil de integrar y fácil de usar. No es necesario pasar días para configurar y personalizar log4Net, con esa clase, listo en minutos.
Aunque actualmente se registra en un archivo, debe ser fácilmente personalizable para iniciar sesión en una base de datos.
Simplemente escribe tus errores de excepción en un archivo de texto. Escribir en el archivo de texto . Una sugerencia es poner el archivo que creaste en un directorio userdata o appdata, para que no tengas problemas con los permisos.
Como esto solo es necesario durante unos meses y se descartará, no hay ninguna razón para ir por la borda con DB. Un simple archivo de texto debería ser suficiente.
Una solución óptima, en mi opinión, sería usar NLog: http://nlog-project.org/
Simplemente instale el paquete config de NuGet: http://www.nuget.org/packages/NLog.Config/ y terminará con la biblioteca y un registrador de archivos preconfigurado ...
Luego en tu código solo necesitas:
// A logger member field:
private readonly Logger logger = LogManager.GetCurrentClassLogger(); // creates a logger using the class name
// use it:
logger.Info(...);
logger.Error(...);
// and also:
logger.ErrorException("text", ex); // which will log the stack trace.
En el archivo de configuración que obtienes, necesitas descomentar las secciones que necesitas:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--
See http://nlog-project.org/wiki/Configuration_file
for information on customizing logging rules and outputs.
-->
<targets>
<!-- add your targets here -->
<!-- UNCOMMENT THIS!
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
</targets>
<rules>
<!-- add your logging rules here -->
<!-- UNCOMMENT THIS!
<logger name="*" minlevel="Trace" writeTo="f" />
-->
</rules>
</nlog>
Edite las propiedades del archivo nlog.config
para
Copy to Output Directory: Copy always