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


166

Existe-t-il un moyen d'écrire dans ce journal des événements:

entrez la description de l'image ici

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




1
"Vous devez créer et configurer la source d'événement avant d'écrire la première entrée avec la source."
Jerther

Il semble que je ne peux pas. Alors, existe-t-il une bonne méthode de secours pour avertir que l'application ne peut pas écrire dans les journaux Windows? Une lime plate semble bonne mais, où? Le dossier d'application aurait encore besoin de certaines autorisations. Mon application est un service Windows.
Jerther

3
Si votre application est un service Windows, une source d'événements est créée automatiquement pour vous. Vous pouvez y accéder via ServiceBase.EventLog. Le nom par défaut de la source est le ServiceName.
Mike Zboray

Réponses:


238

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, utilisez simplement celle existante, qui porte souvent le même nom que le nom de l'EventLog et qui, dans certains cas, comme l'application du journal des événements, peut être accessible sans privilèges administratifs *.

* D'autres cas, où vous ne pouvez pas y accéder directement, sont le Security EventLog, par exemple, qui n'est accessible que par le système d'exploitation.

J'ai utilisé ce code pour écrire directement dans l'application du journal des événements:

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

Comme vous pouvez le voir, la source EventLog est la même que le nom de l'EventLog. La raison de cela peut être trouvée dans Event Sources @ Windows Dev Center (j'ai mis en gras la partie qui fait 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.


1
Mais le texte que vous avez cité indique que vous devez enregistrer la source d'événements sous la clé Journal des événements.
Raymond Chen

1
Ce que je voulais dire, c'est que le nom du journal des événements est souvent le même nom de l'application, c'est pourquoi vous pouvez enregistrer une entrée du journal des événements directement dans le journal des événements sans créer de nouvelle source. J'ai mis en gras le texte quouté pour d'autres lectures.
cloud120

3
Techniquement, le fait de créer la clé de registre consiste à enregistrer la source d'événement. Nommer la clé après le nom de l'application est une convention pour éviter les conflits. Votre réponse est fondamentalement la même que cette réponse .
Raymond Chen

7
Merci pour votre temps Raymond Chen, nous sommes là pour essayer de résoudre ou de suggérer quelque chose qui pourrait aider les autres. Dans ce cas, je crois avoir répondu à la question du sujet: "Y a-t-il un moyen d'écrire dans ce journal des événements: Ou du moins, un autre journal par défaut de Windows, où je n'ai pas besoin d'enregistrer une source d'événements?". -> J'ai répondu: Oui, et je l'ai partagé avec vous. Bien que cela puisse causer des conflits comme vous l'avez dit, il existe un moyen.
cloud120

7
Vous répondez à la question "Existe-t-il un moyen de le faire sans enregistrer une source d'événement?" et votre réponse dit "Créez cette clé de registre afin d'enregistrer une source d'événement." Elle est également identique à une réponse existante.
Raymond Chen

14

Vous pouvez utiliser la classe EventLog, comme expliqué sur Comment: écrire dans le journal des événements d'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 administratifs:

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énement avant d'écrire la première entrée avec la source.


2
C'est le problème que j'ai: je ne peux pas créer la source parce que je n'ai pas ces privilèges, mais je dois quand même enregistrer ce problème quelque part
Jerther

2
Utilisez ensuite un programme d'installation ( stackoverflow.com/questions/1484605/… ) ou connectez-vous à un fichier.
CodeCaster

1
Je vous remercie. Cela m'amène à cette autre question SO: stackoverflow.com/questions/3930529/…
Jerther

@CodeCaster - D'où pouvons-nous accéder à ces journaux? Je veux dire l'emplacement où il est stocké?
Arvind Chourasiya le

1
@Arvind cette question n'a rien à voir avec ma réponse et est une toute nouvelle question.
CodeCaster le

11

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

Il est cependant possible d'utiliser la source "Application" sans. Dans mon test sous Windows 2012 Server r2, j'obtiens cependant l'entrée de journal suivante en utilisant la source "Application":

La description de l'ID d'événement xxxx de l'application source est introuvable. Soit le composant qui déclenche cet événement n'est pas installé sur votre ordinateur local, soit l'installation est endommagée. 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 ont été incluses avec l'événement: {mon message d'entrée d'événement} la ressource de message est présente mais le message n'est pas trouvé dans la table de chaînes / messages

J'ai défini la méthode suivante pour créer la 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 peut être possible d'utiliser la classe EventLogPermission au lieu de ce try / catch mais pas sûr que nous puissions éviter le catch.

Il est également possible de créer la source en externe, par exemple dans un Powershell é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 EventLog peut être créé avec cette source.


10

C'est la classe de journalisation que j'utilise. La méthode private Log () contient EventLog.WriteEntry(), c'est ainsi que vous écrivez réellement 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 n'est pas trop long pour être écrit dans le journal des événements (il tronquera le message). Si le message était trop long, vous obtiendrez 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.

En passant, 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;
        }
    }
}

3
Et ce code le montre. Quel mal y a-t-il à partager ça avec lui? Cela ne pourrait-il pas être utile au PO et à d'autres?
Bob Horn

5
Vous ne pouvez pas écrire dans le journal des événements sans créer une source d'événements , donc ce code ne montre pas cela.
CodeCaster

2
J'aurais encore besoin de créer la source de l'événement, mais vous avez publié votre réponse avant que le titre de la question ne soit mis à jour. Pourtant, je ne connaissais pas la limite de longueur merci.
Jerther

-4

essayer

   System.Diagnostics.EventLog appLog = new System.Diagnostics.EventLog();
   appLog.Source = "This Application's Name";
   appLog.WriteEntry("An entry to the Application event log.");

3
cela nécessite l'enregistrement d'une source d'événement et ne répond donc pas à la question. Désolé.
Jerther

L'idée principale de cette question est d'utiliser la source d'événement "Application".
rcarrillopadron
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.