.Net 서비스 설치 중에 사용자 정의 이벤트 로그 및 이벤트 소스를 생성하는 가장 안정적인 방법은 무엇입니까?

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

문제

.Net Windows 서비스를 설치하는 동안 이벤트 소스를 안정적으로 생성/제거하는 데 어려움을 겪고 있습니다.

내 ProjectInstaller 클래스의 코드는 다음과 같습니다.

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

참조된 Facade 메소드는 로그, 서비스 등의 이름에 대한 문자열을 반환합니다.

이 코드는 대부분의 경우 작동하지만 최근 설치 후 사용자 정의 로그 대신 응용 프로그램 로그에 로그 항목이 표시되기 시작했습니다.그리고 로그에는 다음 오류도 있습니다.

소스( AutoCheckout )의 이벤트 ID( 0 )에 대한 설명을 찾을 수 없습니다.로컬 컴퓨터에는 원격 컴퓨터의 메시지를 표시하는 데 필요한 레지스트리 정보나 메시지 DLL 파일이 없을 수 있습니다./AUXSOURCE= 플래그를 사용하여 이 설명을 검색할 수 있습니다.자세한 내용은 도움말 및 지원을 참조하세요.

어떤 이유로 제거 중에 소스를 제대로 제거하지 않거나 설치 중에 소스를 생성하지 않습니다.

모범 사례에 대한 도움을 주시면 감사하겠습니다.

감사해요!

또한 다음은 로그에 예외를 기록하는 방법에 대한 샘플입니다.

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

stephbu의 답변에 관해서 : 권장 경로는 설치 프로그램 스크립트 및 installutil 또는 Windows 설치 루틴입니다.

서비스 설치를 수행하고 로그를 설정하는 설치 프로젝트를 사용하고 있습니다.installutil.exe를 사용하든 Windows 설정 프로젝트를 사용하든 둘 다 위에 표시된 것과 동일한 ProjectInstaller 클래스를 호출한다고 생각합니다.

재부팅할 때까지 로그가 실제로 제거되지 않으면 테스트 컴퓨터의 상태로 인해 어떻게 오류가 발생할 수 있는지 확인했습니다.문제가 해결되는지 확인하기 위해 더 많은 실험을 해보겠습니다.

편집하다:서비스 설치 시 소스와 로그명을 등록하는 확실한 방법에 관심이 있습니다.따라서 서비스가 이전에 설치된 경우 소스를 제거하거나 후속 설치 중에 소스를 재사용합니다.

나는 아직 그 길을 시도하기 위해 WiX를 배울 기회가 없었습니다.

도움이 되었습니까?

해결책

가장 좋은 권장 사항은 Visual Studio에서 설치 프로젝트를 사용하지 않는 것입니다.매우 심각한 제한이 있습니다.나는 매우 좋은 결과를 얻었습니다 WiX

다른 팁

그만큼 ServiceInstaller 클래스가 자동으로 생성됩니다. EventLogInstaller 이를 자체 Installers 컬렉션에 넣습니다.

다음 코드를 사용해 보세요:

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

여기에 몇 가지가 있습니다.

즉석에서 이벤트 로그와 소스를 생성하는 것은 꽤 눈살을 찌푸리는 일입니다.주로 작업을 수행하는 데 필요한 권한 때문입니다. 실제로 애플리케이션에 그러한 권한을 부여하고 싶지는 않습니다.

또한 이벤트 로그나 소스를 삭제하면 항목만 삭제됩니다. 진실로 서버가 재부팅되면 삭제되므로 상자를 튕기지 않고 항목을 삭제하고 다시 생성하면 이상한 상태가 될 수 있습니다.또한 메타데이터가 레지스트리에 저장되는 방식으로 인해 발생하는 이름 충돌에 대한 기록되지 않은 규칙이 많이 있습니다.

권장 경로는 설치 프로그램 스크립트 및 installutil 또는 Windows 설치 루틴입니다.

나는 이벤트 로그가 들어가는 "이상한 상태"에 대해 stephbu의 의견에 동의해야 합니다. 이전에 그런 일을 겪은 적이 있습니다.내가 추측하자면, 당신의 어려움 중 일부는 거기에 있습니다.

그러나 제가 아는 응용 프로그램에서 이벤트 로깅을 수행하는 가장 좋은 방법은 실제로 TraceListener를 사용하는 것입니다.서비스의 app.config를 통해 구성할 수 있습니다.

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

해당 페이지 중간 부분에는 EventLog 속성을 사용하여 기록하려는 EventLog를 지정하는 방법을 설명하는 섹션이 있습니다.

도움이 되길 바랍니다.

나도 팔로우했다 지옥의 기본적으로 표준 디자이너 생성 클래스(기본 개체 "ServiceProcessInstaller1" 및 "ServiceInstaller1")를 사용했다는 점만 제외하면 제안입니다.나는 이것이 약간 더 간단한 버전이기 때문에 이것을 게시하기로 결정했습니다.또한 저는 VB에서 일하고 있기 때문에 사람들은 때때로 VB 방식을 보고 싶어합니다.

처럼 타르테오드 즉, 디자이너가 생성한 ProjectInstaller 클래스를 수정해서는 안 됩니다. 프로젝트설치자.Designer.vb 파일을 제출했지만 당신은 ~할 수 있다 에서 코드를 수정하세요. 프로젝트설치자.vb 파일.표준 '설치 프로그램 추가' 메커니즘을 사용하여 일반 ProjectInstaller를 생성한 후 내가 변경한 유일한 변경 사항은 ProjectInstaller 클래스의 New()입니다.일반적인 "InitializeComponent()" 호출 후에 다음 코드를 삽입했습니다.

  ' 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)

설치 프로그램이 예상대로 작동했습니다. ~ 아니다 응용 프로그램 로그에 이벤트 소스를 생성하는 대신 새 사용자 지정 로그 파일에 생성합니다.

그러나 한 서버에서 약간의 혼란이 생길 ​​정도로 충분히 망쳤습니다.사용자 정의 로그의 문제점은 이벤트 소스 이름이 잘못된 로그 파일(예:새 사용자 정의 로그 대신 '응용 프로그램' 로그), 먼저 소스 이름을 삭제해야 합니다.그런 다음 기계가 재부팅되었습니다.그러면 올바른 로그에 연결하여 소스를 생성할 수 있습니다.Microsoft 도움말에는 다음과 같이 명확하게 명시되어 있습니다. EventLogInstaller 클래스 설명):

소스 속성이 컴퓨터의 다른 이벤트 로그에 등록 된 소스 이름과 일치하는 경우 설치 메소드가 예외가 발생합니다.

따라서 서비스가 시작될 때 호출되는 이 함수도 내 서비스에 있습니다.

   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

함수가 False를 반환하면 서비스 시작 코드는 단순히 서비스를 중지합니다.이 기능을 사용하면 결국 올바른 이벤트 로그 파일과 관련된 올바른 이벤트 소스 이름을 얻을 수 있습니다.컴퓨터를 한 번 재부팅해야 할 수도 있습니다.서비스를 두 번 이상 시작해야 할 수도 있습니다.

나는 같은 문제를 겪고 있습니다.내 경우에는 Windows 설치 프로그램이 내 서비스와 동일한 이름의 이벤트 소스를 자동으로 추가하는 것 같으며 이로 인해 문제가 발생하는 것 같습니다.Windows 서비스와 로그 소스에 동일한 이름을 사용하고 있습니까?이벤트 로그 소스가 서비스 이름과 다르게 호출되도록 변경해 보세요.

방금 MSDN 포럼에 이에 대한 솔루션을 게시했는데, 표준 설정 MSI 프로젝트를 사용하여 이 문제를 해결할 수 있었습니다.내가 한 일은 PreInstall 및 Committed 이벤트에 코드를 추가하는 것이었습니다. 이는 다른 모든 것을 그대로 유지할 수 있음을 의미합니다.

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

아직 존재하지 않는 이벤트 소스만 제거하거나 생성하기 위해 코드를 조금 더 수정할 수 있지만(로그 이름은 설치 프로그램에 대해 어딘가에 저장해야 하지만) 내 애플리케이션 코드가 실제로 실행될 때 이벤트 소스를 생성하기 때문입니다. 그러면 나에게는 아무 소용이 없습니다.이미 이벤트가 있는 경우 이벤트 소스가 이미 있어야 합니다.서비스가 생성되었는지 확인하려면 서비스를 자동으로 시작하면 됩니다.

내가 시작하고 있는 서비스와 동일한 이름을 가진 이벤트 소스를 등록하려고 했기 때문에 비슷한 이상한 동작을 경험했습니다.

DisplayName도 이벤트 소스와 동일한 이름으로 설정되어 있습니다.

서비스를 시작할 때 Windows는 소스를 DisplayName으로 사용하여 응용 프로그램 로그에 "서비스가 성공적으로 시작되었습니다"라는 항목을 기록한 것을 발견했습니다.이게 등록 효과가 있는 것 같았어요 애플리케이션 이름 응용 프로그램 로그와 함께.

내 이벤트 로거 클래스에서 나중에 등록을 시도했습니다. 애플리케이션 이름 다른 이벤트 로그가 있는 원본이지만 새 이벤트 로그 항목을 추가하면 항상 응용 프로그램 로그에 추가됩니다.

또한 "소스의 이벤트 ID( 0 )에 대한 설명" 메시지도 여러 번 받았습니다.

해결 방법으로 간단히 DisplayName과 약간 다른 이름으로 메시지 소스를 등록했고 그 이후로 계속 작동했습니다.아직 시도하지 않았다면 시도해 볼 가치가 있습니다.

문제는 기본적으로 "응용 프로그램" EventLog에 서비스 이름으로 이벤트 소스를 등록하는 installutil에서 발생합니다.나는 아직도 이런 쓰레기 같은 일을 멈추는 방법을 찾고 있습니다.installutil의 동작에 영향을 줄 수 있다면 정말 좋을 것입니다.

수행원 지옥의 제안으로 문제가 해결되었습니다.예제에 표시된 지점에서 기본 이벤트 로그 설치 프로그램을 종료하면 설치 프로그램이 응용 프로그램 이벤트 로그에 내 Windows 서비스를 자동으로 등록하지 못했습니다.

이 실망스러운 문제를 해결하는 데 너무 많은 시간이 낭비되었습니다.대단히 감사합니다!

FWIW, VS가 모드에 대해 잉꼬를 일으키지 않고는 디자이너가 생성한 ProjectInstaller 클래스 내에서 코드를 수정할 수 없었습니다.디자이너가 생성한 코드를 폐기하고 수동으로 수업에 들어갔습니다.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application\MY_CUSTOM_SOURCE_NAME_HERE에 빈 레지스트리 키를 추가하면 제대로 작동하는 것 같습니다.

기본 동작(즉, 프로젝트 설치 프로그램이 애플리케이션 로그에 서비스 이름으로 이벤트 로그 소스를 생성하는 것)을 변경하는 쉬운 방법은 프로젝트 설치 프로그램의 생성자를 다음과 같이 쉽게 수정하는 것입니다.

[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;
        }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top