Was ist der zuverlässigste Weg, um ein benutzerdefiniertes Ereignisprotokoll und Ereignisquelle während der Installation eines .Net-Service zu erstellen

StackOverflow https://stackoverflow.com/questions/115488

Frage

Ich habe zuverlässig Schwierigkeiten zu schaffen / Entfernen von Ereignisquellen bei der Installation meines .NET Windows-Dienstes.

Hier ist der Code aus meiner Klasse Project:

// Create Process Installer
ServiceProcessInstaller spi = new ServiceProcessInstaller();
spi.Account = ServiceAccount.LocalSystem;

// Create Service
ServiceInstaller si = new ServiceInstaller();
si.ServiceName = Facade.GetServiceName();
si.Description = "Processes ...";
si.DisplayName = "Auto Checkout";
si.StartType = ServiceStartMode.Automatic;

// Remove Event Source if already there
if (EventLog.SourceExists("AutoCheckout"))
    EventLog.DeleteEventSource("AutoCheckout");

// Create Event Source and Event Log     
EventLogInstaller log = new EventLogInstaller();
log.Source = "AutoCheckout";
log.Log = "AutoCheckoutLog";

Installers.AddRange(new Installer[] { spi, si, log });

Die Fassade Methoden verwiesen nur die Saiten für den Namen des Protokolls zurückzukehren, Service, etc.

Dieser Code funktioniert die meiste Zeit, aber vor kurzem nach der Installation begann ich meine Log-Einträge immer im Anwendungsprotokoll zeigt sich anstelle des benutzerdefinierten Protokoll. Und die folgenden Fehler sind in dem Protokoll auch:

  

Die Beschreibung von Ereigniskennung (0) in Quelle (AutoCheckout) kann nicht gefunden werden. Der lokale Computer verfügt nicht über die erforderlichen Registrierungsinformationen oder DLL-Meldungsdateien Meldungen von einem Remotecomputer anzuzeigen. Sie können das / AUXSOURCE = Flag verwenden, um diese Beschreibung abzurufen; Hilfe- und Support für weitere Einzelheiten.

Aus irgendeinem Grunde ist es entweder nicht richtig die Quelle während der Deinstallation zu entfernen oder sie schafft es nicht während der Installation.

Jede Hilfe mit Best Practices wird hier geschätzt.

Danke!

Darüber hinaus ist hier ein Beispiel, wie ich schreibe Ausnahmen in das Protokoll:

// Write to Log
EventLog.WriteEntry(Facade.GetEventLogSource(), errorDetails, EventLogEntryType.Error, 99);

In Bezug auf stephbu Antwort:. Der empfohlene Weg ist ein Installationsskript und installutil oder eine Windows Setup-Routine

Ich bin mit einem Setup-Projekt, das die Installation des Service durchführt und das Protokoll einrichtet. Ob ich die installutil.exe oder das Windows-Setup-Projekt verwenden, glaube ich, dass sie beide die gleiche Klasse Project nennen ich oben zeigen.

Ich sehe, wie der Zustand meiner Test-Maschine die Fehler verursachen könnte, wenn das Protokoll nicht wirklich bis zum Neustart entfernt wird. Ich werde mehr experimentieren, um zu sehen, ob das das Problem löst.

Edit: Ich bin in einem sicheren Weg, interessiere die Quelle und die Protokollnamen während der Installation des Service zu registrieren. Also, wenn hatte der Dienst zuvor installiert worden ist, wäre es die Quelle entfernen oder wieder verwendet die Quelle während der nachfolgenden Installationen.

Ich habe noch nicht die Gelegenheit hatte, WiX zu lernen, diesen Weg zu versuchen.

War es hilfreich?

Lösung

Die beste Empfehlung wäre nicht das Setup-Projekt in Visual Studio zu verwenden. Es hat sehr starke Einschränkungen. Ich hatte sehr gute Ergebnisse mit WiX

Andere Tipps

Die ServiceInstaller Klasse erstellt automatisch ein EventLogInstaller und legt es in seiner eigenen Installateuren Sammlung.

Versuchen Sie diesen Code ein:

ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
serviceProcessInstaller.Password = null;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;

// serviceInstaller
ServiceInstaller serviceInstaller = new ServiceInstaller();
serviceInstaller.ServiceName = "MyService";
serviceInstaller.DisplayName = "My Service";
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.Description = "My Service Description";
// kill the default event log installer
serviceInstaller.Installers.Clear(); 

// Create Event Source and Event Log     
EventLogInstaller logInstaller = new EventLogInstaller();
logInstaller.Source = "MyService"; // use same as ServiceName
logInstaller.Log = "MyLog";

// Add all installers
this.Installers.AddRange(new Installer[] {
   serviceProcessInstaller, serviceInstaller, logInstaller
});

Paar Dinge hier

Erstellen von Ereignisprotokollen und Quellen on the fly ist ziemlich verpönt. vor allem wegen der Rechte zum Ausführen der Aktion erforderlich -. Sie wollen nicht wirklich Ihre Anwendungen mit dieser Macht segnen

Außerdem, wenn Sie ein Ereignisprotokoll löschen oder den Eintrag Quelle nur truely gelöscht, wenn der Server neu gestartet, so dass Sie in wierd Staaten erhalten können, wenn Sie Einträge löschen und neu erstellen, ohne die Box heraus aufprallen. Darüber hinaus gibt es eine Reihe von ungeschriebenen Regeln über Konflikte aufgrund der Art und Weise der Benennung der Metadaten in der Registrierung gespeichert werden.

Der empfohlene Weg ist ein Installationsskript und installutil oder eine Windows Setup-Routine.

ich mit stephbu über die „weird states“ zustimmen, dass das Ereignisprotokoll wird in, ich habe, bevor sie in die volle Funktionalität. Wenn ich zu erraten waren, liegen einige Ihrer Schwierigkeiten gibt.

Allerdings ist der beste Weg, die ich kenne die Ereignisprotokollierung in der Anwendung zu tun ist, tatsächlich mit einem Tracelistener. Sie können sie über den Dienst des app.config konfigurieren:

http://msdn.microsoft.com/en -US / library / system.diagnostics.eventlogtracelistener.aspx

Es gibt einen Abschnitt in der Nähe der Mitte dieser Seite, die beschreibt, wie die EventLog-Eigenschaft verwenden, um die EventLog Sie angeben möchten, schreiben.

Ich hoffe, das hilft.

Ich folgte auch HELB des Vorschlag, mit der Ausnahme, dass ich grundsätzlich verwendet, die Standard-Designer generierten Klassen (die Standardobjekte "ServiceProcessInstaller1" und "ServiceInstaller1"). Ich beschloss, dies zu schreiben, da es sich um eine etwas einfachere Version ist; und auch, weil ich arbeite in VB und die Leute manchmal mögen den VB-Weg zu sehen.

tartheode , sagte, sollten Sie den Designer generierten Project Klasse in der nicht ändern ProjectInstaller.Designer.vb Datei, aber Sie können ändern Sie den Code in der ProjectInstaller.vb Datei. () Der Klasse Project nach einer normalen Project Erstellung (mit dem Standard ‚Add Installer‘ -Mechanismus), habe ich die einzige Änderung war im Neuen gemacht. Nach dem normalen "InitializeComponent ()" nennen, ich eingefügt diesen Code:

  ' remove the default event log installer 
  Me.ServiceInstaller1.Installers.Clear()

  ' Create an EventLogInstaller, and set the Event Source and Event Log      
  Dim logInstaller As New EventLogInstaller
  logInstaller.Source = "MyServiceName"
  logInstaller.Log = "MyCustomEventLogName"

  ' Add the event log installer
  Me.ServiceInstaller1.Installers.Add(logInstaller)

Das funktionierte wie erwartet, dass das Installationsprogramm hat nicht Erstellen Sie die Ereignisquelle in dem Anwendungsprotokoll, sondern in der neuen benutzerdefinierten Protokolldatei erstellt.

Allerdings hatte ich genug herumgeschraubt, dass ich ein bisschen ein Durcheinander auf einem Server hatte. Das Problem mit den benutzerdefinierten Protokolle ist, dass, wenn die Ereignisquelle Namen dem falsch Protokolldatei (zB die ‚Anwendung‘ log statt Ihrer neuen benutzerdefinierten log) zugeordnet existiert, dann muss der Name der Quelle zuerst gelöscht werden ; dann wird die Maschine neu gestartet; dann kann die Quelle mit Zuordnung zu dem korrekten Protokoll erstellt werden. Die Microsoft-Hilfe eindeutig fest (in der Eventloginstaller-Klasse Beschreibung ):

  

Das Install-Methode löst eine Ausnahme   wenn die Source-Eigenschaft übereinstimmt ein   Quelle Name, der für ein registriert ist   verschiedenes Ereignisprotokoll auf dem Computer.

Daher habe ich diese Funktion auch in meinem Dienst, der aufgerufen wird, wenn der Dienst gestartet wird:

   Private Function EventLogSourceNameExists() As Boolean
      'ensures that the EventSource name exists, and that it is associated to the correct Log 

      Dim EventLog_SourceName As String = Utility.RetrieveAppSetting("EventLog_SourceName")
      Dim EventLog_LogName As String = Utility.RetrieveAppSetting("EventLog_LogName")

      Dim SourceExists As Boolean = EventLog.SourceExists(EventLog_SourceName)
      If Not SourceExists Then
         ' Create the source, if it does not already exist.
         ' An event log source should not be created and immediately used.
         ' There is a latency time to enable the source, it should be created
         ' prior to executing the application that uses the source.
         'So pass back a False to cause the service to terminate.  User will have 
         'to re-start the application to make it work.  This ought to happen only once on the 
         'machine on which the service is newly installed

         EventLog.CreateEventSource(EventLog_SourceName, EventLog_LogName)  'create as a source for the SMRT event log
      Else
         'make sure the source is associated with the log file that we want
         Dim el As New EventLog
         el.Source = EventLog_SourceName
         If el.Log <> EventLog_LogName Then
            el.WriteEntry(String.Format("About to delete this source '{0}' from this log '{1}'.  You may have to kill the service using Task Manageer.  Then please reboot the computer; then restart the service two times more to ensure that this event source is created in the log {2}.", _
            EventLog_SourceName, el.Log, EventLog_LogName))

            EventLog.DeleteEventSource(EventLog_SourceName)
            SourceExists = False  'force a close of service
         End If
      End If
      Return SourceExists
   End Function

Wenn die Funktion False zurückgibt, stoppt der Dienststartcode einfach den Dienst. Diese Funktion sorgt dafür ziemlich viel, dass Sie schließlich die richtige Ereignisquelle Name auf die richtige Ereignisprotokolldatei zugeordnet bekommen. Sie können einmal den Rechner neu starten müssen; und Sie können den Dienst starten mehr als einmal versuchen.

Ich habe die gleichen Probleme. In meinem Fall scheint es, dass Windows Installer die Ereignisquelle ist das Hinzufügen, die mit dem gleichen Namen wie mein Service ist automatisch und dies scheint Probleme zu verursachen. Verwenden Sie den gleichen Namen für den Windows-Dienst und für die Protokollquelle? Versuchen Sie, es so, dass Ihr Ereignisprotokoll Quelle anders genannt wird, dann wird der Name des Dienstes.

Ich habe gerade gebucht, eine Lösung für diese auf MSDN-Foren über die auf das war ich um diese mit einem Standard-Setup-MSI-Projekt zu bekommen verwaltet. Was ich tat, war Code an die vorinstallieren und Committed Ereignisse hinzuzufügen, was bedeutete, dass ich alles behalten konnte sonst genau so, wie es war:

SortedList<string, string> eventSources = new SortedList<string, string>();
private void serviceProcessInstaller_BeforeInstall(object sender, InstallEventArgs e)
{
  RemoveServiceEventLogs();
}

private void RemoveServiceEventLogs()
{
  foreach (Installer installer in this.Installers)
    if (installer is ServiceInstaller)
    {
      ServiceInstaller serviceInstaller = installer as ServiceInstaller;
      if (EventLog.SourceExists(serviceInstaller.ServiceName))
      {
        eventSources.Add(serviceInstaller.ServiceName, EventLog.LogNameFromSourceName(serviceInstaller.ServiceName, Environment.MachineName));
        EventLog.DeleteEventSource(serviceInstaller.ServiceName);
      }
    }
}

private void serviceProcessInstaller_Committed(object sender, InstallEventArgs e)
{
  RemoveServiceEventLogs();
  foreach (KeyValuePair<string, string> eventSource in eventSources)
  {
    if (EventLog.SourceExists(eventSource.Key))
      EventLog.DeleteEventSource(eventSource.Key);

    EventLog.CreateEventSource(eventSource.Key, eventSource.Value);
  }
}

Der Code könnte die Ereignisquellen etwas weiter entfernt nur modifiziert werden, die nicht bereits existieren oder sie erstellen (obwohl die logname brauchen würde irgendwo gegen den Installateur gespeichert werden), aber da mein Anwendungscode tatsächlich die Ereignisquellen erzeugt wie es läuft dann gibt es für mich keinen Sinn. Falls bereits Ereignisse sind dann sollte es schon eine Ereignisquelle sein. Um sicherzustellen, dass sie erstellt werden, können Sie einfach automatisch den Dienst starten.

Ich erleben ein ähnliches seltsames Verhalten, weil ich versuchte, eine Ereignisquelle mit dem gleichen Namen wie der Dienst registrieren Ich begann.

Ich stelle fest, dass Sie auch die Display auf den gleichen Namen wie die Ereignisquelle eingestellt haben.

Auf den Service ab und startet, fanden wir, dass Windows angemeldet ein „Service erfolgreich gestartet“ im Anwendungsprotokoll, mit Quelle als Display. Dies schien die Wirkung der Registrierung Anwendungsname mit dem Anwendungsprotokoll zu haben.

In meiner Event Logger Klasse habe ich versucht, später zu registrieren Anwendungsname als Quelle mit einem anderen Ereignisprotokoll, aber wenn es darum ging, neue Ereignisprotokolleinträge auf dem Hinzufügen sie hätte immer zu dem Anwendungsprotokoll hinzugefügt.

Ich habe auch die „Die Beschreibung von Ereigniskennung (0) in der Quelle“ Nachricht mehrmals.

Als eine Arbeit um mich einfach die Nachrichtenquelle mit einem etwas anderen Namen den Display registriert, und es ist seitdem gearbeitet. Es wäre ein Versuch wert, diese, wenn Sie nicht bereits haben.

Das Problem kommt von installutil die standardmäßig eine Ereignisquelle mit Ihren Dienstleistungen Namen registriert in der „Application“ EventLog. Ich bin noch auf der Suche nach einem Weg, es zu tun mit diesem Mist zu stoppen. Es wäre wirklich schön, wenn man das Verhalten von installutil beeinflussen könnte: (

Im Anschluss an HELB des Vorschlag löste das Problem für mich. Töten Sie die Standardereignisprotokoll-Installer, an dem Punkt in seinem Beispiel angegeben ist, verhindert das Installationsprogramm automatisch meine Windows-Dienst unter dem Anwendungsereignisprotokoll registriert.

Viel zu viel Zeit wurde versucht, verliert diese frustrierend Marotte zu lösen. Dank einer Million!

FWIW, kann ich den Code in meinem Designer generierte Project Klasse nicht ändern, ohne dass VS über die Mods nörgeln. Ich verschrottet den Designer generierten Code und manuell die Klasse eingetragen.

einen leeren Registrierungsschlüssel HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Service Hinzufügen \ eventlog \ Application \ MY_CUSTOM_SOURCE_NAME_HERE scheint gut zu funktionieren.

Eine einfache Möglichkeit, das Standardverhalten zu ändern (das heißt, dass das Projekt Installer eine Ereignisprotokoll-Quelle mit dem Namen Ihres Service im Anwendungsprotokoll erstellt) ist auf einfache Weise den Konstruktor des Projekt Installateur zu ändern, wie folgend:

[RunInstaller( true )]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
    public ProjectInstaller()
    {
        InitializeComponent();

        //Skip through all ServiceInstallers.
        foreach( ServiceInstaller ThisInstaller in Installers.OfType<ServiceInstaller>() )
        {
            //Find the first default EventLogInstaller.
            EventLogInstaller ThisLogInstaller = ThisInstaller.Installers.OfType<EventLogInstaller>().FirstOrDefault();
            if( ThisLogInstaller == null )
                continue;

            //Modify the used log from "Application" to the same name as the source name. This creates a source in the "Applications and Services log" which separates your service logs from the default application log.
            ThisLogInstaller.Log = ThisLogInstaller.Source;
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top