¿Hay alguna manera de escribir en este registro de eventos?
O al menos, algún otro registro predeterminado de Windows, donde no tengo que registrar un origen de eventos ?
ServiceBase.EventLog
. El nombre predeterminado de la Fuente es ServiceName.
¿Hay alguna manera de escribir en este registro de eventos?
O al menos, algún otro registro predeterminado de Windows, donde no tengo que registrar un origen de eventos ?
ServiceBase.EventLog
. El nombre predeterminado de la Fuente es ServiceName.
Respuestas:
Sí, hay una manera de escribir en el registro de eventos que está buscando. No necesita crear una nueva fuente, simplemente use la existente, que a menudo tiene el mismo nombre que el nombre de EventLog y también, en algunos casos, como la aplicación de registro de eventos, puede ser accesible sin privilegios administrativos *.
* Otros casos, en los que no puede acceder directamente, son Security EventLog, por ejemplo, al que solo accede el sistema operativo.
Utilicé este código para escribir directamente en la aplicación de registro de eventos:
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Log message example", EventLogEntryType.Information, 101, 1);
}
Como puede ver, la fuente de EventLog es la misma que el nombre de EventLog. La razón de esto se puede encontrar en Event Sources @ Windows Dev Center (en negrita la parte que se refiere al nombre de la fuente):
Cada registro en la clave Eventlog contiene subclaves llamadas orígenes de eventos. El origen del evento es el nombre del software que registra el evento. A menudo es el nombre de la aplicación o el nombre de un subcomponente de la aplicación si la aplicación es grande. Puede agregar un máximo de 16,384 orígenes de eventos al registro.
Puede usar la clase EventLog, como se explica en Cómo: Escribir en el registro de eventos de la aplicación (Visual C #) :
var appLog = new EventLog("Application");
appLog.Source = "MySource";
appLog.WriteEntry("Test log message");
Sin embargo, deberá configurar esta fuente "MySource" utilizando privilegios administrativos:
Use WriteEvent y WriteEntry para escribir eventos en un registro de eventos. Debe especificar un origen de evento para escribir eventos; debe crear y configurar el origen del evento antes de escribir la primera entrada con el origen.
Como se indica en MSDN (por ejemplo, https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog(v=vs.110).aspx ), verificar una fuente no existente y crear una fuente requiere administración privilegio.
Sin embargo, es posible utilizar la fuente "Aplicación" sin. Sin embargo, en mi prueba en Windows 2012 Server r2, obtengo la siguiente entrada de registro utilizando la fuente "Aplicación":
No se puede encontrar la descripción del evento ID xxxx de la aplicación de origen. El componente que genera este evento no está instalado en su computadora local o la instalación está dañada. Puede instalar o reparar el componente en la computadora local. Si el evento se originó en otra computadora, la información de la pantalla debía guardarse con el evento. La siguiente información se incluyó con el evento: {mi mensaje de entrada de evento} el recurso del mensaje está presente pero el mensaje no se encuentra en la tabla de cadena / mensaje
Definí el siguiente método para crear la fuente:
private string CreateEventSource(string currentAppName)
{
string eventSource = currentAppName;
bool sourceExists;
try
{
// searching the source throws a security exception ONLY if not exists!
sourceExists = EventLog.SourceExists(eventSource);
if (!sourceExists)
{ // no exception until yet means the user as admin privilege
EventLog.CreateEventSource(eventSource, "Application");
}
}
catch (SecurityException)
{
eventSource = "Application";
}
return eventSource;
}
Lo estoy llamando con currentAppName = AppDomain.CurrentDomain.FriendlyName
Puede ser posible usar la clase EventLogPermission en lugar de este intento / captura, pero no estoy seguro de que podamos evitar la captura.
También es posible crear la fuente externamente, por ejemplo, en Powershell elevado:
New-EventLog -LogName Application -Source MyApp
Luego, usar 'MyApp' en el método anterior NO generará una excepción y EventLog se puede crear con esa fuente.
Esta es la clase de registrador que uso. El método privado Log () tiene EventLog.WriteEntry()
, que es cómo realmente escribe en el registro de eventos. Incluyo todo este código aquí porque es útil. Además del registro, esta clase también se asegurará de que el mensaje no sea demasiado largo para escribir en el registro de eventos (truncará el mensaje). Si el mensaje fuera demasiado largo, obtendría una excepción. La persona que llama también puede especificar la fuente. Si la persona que llama no lo hace, esta clase obtendrá la fuente. Espero eso ayude.
Por cierto, puede obtener un ObjectDumper de la web. No quería publicar todo eso aquí. Tengo el mío de aquí:C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\1033\CSharpSamples.zip\LinqSamples\ObjectDumper
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Xanico.Core.Utilities;
namespace Xanico.Core
{
/// <summary>
/// Logging operations
/// </summary>
public static class Logger
{
// Note: The actual limit is higher than this, but different Microsoft operating systems actually have
// different limits. So just use 30,000 to be safe.
private const int MaxEventLogEntryLength = 30000;
/// <summary>
/// Gets or sets the source/caller. When logging, this logger class will attempt to get the
/// name of the executing/entry assembly and use that as the source when writing to a log.
/// In some cases, this class can't get the name of the executing assembly. This only seems
/// to happen though when the caller is in a separate domain created by its caller. So,
/// unless you're in that situation, there is no reason to set this. However, if there is
/// any reason that the source isn't being correctly logged, just set it here when your
/// process starts.
/// </summary>
public static string Source { get; set; }
/// <summary>
/// Logs the message, but only if debug logging is true.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="debugLoggingEnabled">if set to <c>true</c> [debug logging enabled].</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogDebug(string message, bool debugLoggingEnabled, string source = "")
{
if (debugLoggingEnabled == false) { return; }
Log(message, EventLogEntryType.Information, source);
}
/// <summary>
/// Logs the information.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogInformation(string message, string source = "")
{
Log(message, EventLogEntryType.Information, source);
}
/// <summary>
/// Logs the warning.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogWarning(string message, string source = "")
{
Log(message, EventLogEntryType.Warning, source);
}
/// <summary>
/// Logs the exception.
/// </summary>
/// <param name="ex">The ex.</param>
/// <param name="source">The name of the app/process calling the logging method. If not provided,
/// an attempt will be made to get the name of the calling process.</param>
public static void LogException(Exception ex, string source = "")
{
if (ex == null) { throw new ArgumentNullException("ex"); }
if (Environment.UserInteractive)
{
Console.WriteLine(ex.ToString());
}
Log(ex.ToString(), EventLogEntryType.Error, source);
}
/// <summary>
/// Recursively gets the properties and values of an object and dumps that to the log.
/// </summary>
/// <param name="theObject">The object to log</param>
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Xanico.Core.Logger.Log(System.String,System.Diagnostics.EventLogEntryType,System.String)")]
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "object")]
public static void LogObjectDump(object theObject, string objectName, string source = "")
{
const int objectDepth = 5;
string objectDump = ObjectDumper.GetObjectDump(theObject, objectDepth);
string prefix = string.Format(CultureInfo.CurrentCulture,
"{0} object dump:{1}",
objectName,
Environment.NewLine);
Log(prefix + objectDump, EventLogEntryType.Warning, source);
}
private static void Log(string message, EventLogEntryType entryType, string source)
{
// Note: I got an error that the security log was inaccessible. To get around it, I ran the app as administrator
// just once, then I could run it from within VS.
if (string.IsNullOrWhiteSpace(source))
{
source = GetSource();
}
string possiblyTruncatedMessage = EnsureLogMessageLimit(message);
EventLog.WriteEntry(source, possiblyTruncatedMessage, entryType);
// If we're running a console app, also write the message to the console window.
if (Environment.UserInteractive)
{
Console.WriteLine(message);
}
}
private static string GetSource()
{
// If the caller has explicitly set a source value, just use it.
if (!string.IsNullOrWhiteSpace(Source)) { return Source; }
try
{
var assembly = Assembly.GetEntryAssembly();
// GetEntryAssembly() can return null when called in the context of a unit test project.
// That can also happen when called from an app hosted in IIS, or even a windows service.
if (assembly == null)
{
assembly = Assembly.GetExecutingAssembly();
}
if (assembly == null)
{
// From http://stackoverflow.com/a/14165787/279516:
assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
}
if (assembly == null) { return "Unknown"; }
return assembly.GetName().Name;
}
catch
{
return "Unknown";
}
}
// Ensures that the log message entry text length does not exceed the event log viewer maximum length of 32766 characters.
private static string EnsureLogMessageLimit(string logMessage)
{
if (logMessage.Length > MaxEventLogEntryLength)
{
string truncateWarningText = string.Format(CultureInfo.CurrentCulture, "... | Log Message Truncated [ Limit: {0} ]", MaxEventLogEntryLength);
// Set the message to the max minus enough room to add the truncate warning.
logMessage = logMessage.Substring(0, MaxEventLogEntryLength - truncateWarningText.Length);
logMessage = string.Format(CultureInfo.CurrentCulture, "{0}{1}", logMessage, truncateWarningText);
}
return logMessage;
}
}
}
tratar
System.Diagnostics.EventLog appLog = new System.Diagnostics.EventLog();
appLog.Source = "This Application's Name";
appLog.WriteEntry("An entry to the Application event log.");