web-dev-qa-db-fra.com

Écrire dans le journal des événements de l'application Windows

Est-il possible d'écrire dans ce journal des événements:

enter image description here

Ou du moins, un autre journal par défaut de Windows, où je n'ai pas besoin d'enregistrer une source d'événement ?

98
Jerther

Oui, il existe un moyen d'écrire dans le journal des événements que vous recherchez. Vous n'avez pas besoin de créer une nouvelle source, il vous suffit d'utiliser celle qui existe, qui porte souvent le même nom que le nom du journal des événements et qui peut, dans certains cas, comme l'application du journal des événements, être accessible sans privilèges d'administrateur *.

* Dans d'autres cas, vous ne pouvez pas y accéder directement, par exemple, le journal des événements de sécurité auquel seul le système d'exploitation a accès.

J'ai utilisé ce code pour écrire directement dans le journal des événements Application:

using (EventLog eventLog = new EventLog("Application")) 
{
    eventLog.Source = "Application"; 
    eventLog.WriteEntry("Log message example", EventLogEntryType.Information, 101, 1); 
}

Comme vous pouvez le constater, la source EventLog est identique à son nom. La raison de ceci se trouve dans Sources d'événements @ Centre de développement Windows (J'ai mis en gras la partie faisant référence au nom de la source):

Chaque journal de la clé Eventlog contient des sous-clés appelées sources d'événements. La source de l'événement est le nom du logiciel qui enregistre l'événement. Il s'agit souvent du nom de l'application ou du nom d'un sous-composant de l'application si l'application est volumineuse. Vous pouvez ajouter un maximum de 16 384 sources d'événements au registre.

169
cloud120

Vous pouvez utiliser la classe EventLog, comme expliqué dans Comment: écrire dans le journal des événements de l'application (Visual C #) :

var appLog = new EventLog("Application");
appLog.Source = "MySource";
appLog.WriteEntry("Test log message");

Cependant, vous devrez configurer cette source "MySource" en utilisant les privilèges d'administrateur:

Utilisez WriteEvent et WriteEntry pour écrire des événements dans un journal des événements. Vous devez spécifier une source d'événements pour écrire des événements. vous devez créer et configurer la source d'événements avant d'écrire la première entrée avec la source.

9
CodeCaster

C'est la classe de journalisation que j'utilise. La méthode privée Log () contient EventLog.WriteEntry(), ce qui vous permet d'écrire dans le journal des événements. J'inclus tout ce code ici parce que c'est pratique. En plus de la journalisation, cette classe s'assurera également que le message ne sera pas trop long à écrire dans le journal des événements (il tronquera le message). Si le message était trop long, vous auriez une exception. L'appelant peut également spécifier la source. Si l'appelant ne le fait pas, cette classe obtiendra la source. J'espère que ça aide.

Au fait, vous pouvez obtenir un ObjectDumper sur le Web. Je ne voulais pas poster tout ça ici. J'ai le mien d'ici: 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;
        }
    }
}
8
Bob Horn

Comme indiqué dans MSDN (par exemple, https://msdn.Microsoft.com/en-us/library/system.diagnostics.eventlog(v=vs.110).aspx ), vérification d'une source non existante et création une source nécessite des privilèges d'administrateur.

Il est toutefois possible d'utiliser source "Application" sans . Lors de mon test sous Windows 2012 Server r2, j'obtiens toutefois l'entrée de journal suivante à l'aide de la source "Application":

La description de l'ID d'événement xxxx de l'application source est introuvable. Le composant qui déclenche cet événement n'est pas installé sur votre ordinateur local ou l'installation est corrompue. Vous pouvez installer ou réparer le composant sur l'ordinateur local . Si l'événement provenait d'un autre ordinateur, les informations d'affichage devaient être enregistrées avec l'événement . Les informations suivantes étaient incluses dans l'événement: {mon message d'entrée d'événement} la ressource de message est présente mais le message est introuvable dans la table string/message

J'ai défini la méthode suivante pour créer le source:

    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;
    }

Je l'appelle avec currentAppName = AppDomain.CurrentDomain.FriendlyName

Il serait peut-être possible d'utiliser la classe EventLogPermission à la place de cet essai/attrape, mais nous ne sommes pas certains de pouvoir éviter l'attrape.

Il est également possible de créer la source en externe, par exemple dans Powershell surélevé:

New-EventLog -LogName Application -Source MyApp

Ensuite, l'utilisation de 'MyApp' dans la méthode ci-dessus NE générera PAS d'exception et le journal des événements peut être créé avec cette source.

4
EricBDev

EventLog Class Fournit une interaction avec les journaux des événements Windows . Cet exemple vous montre comment écrire dans EventViewer.

        public void WriteEventLog(string message)
        {

           EventLog eventLog = new EventLog() { Source = "application Name",           
           EnableRaisingEvents = true };
           eventLog.WriteEntry( message);

        }
0
Mohamad-Al-Ibrahim