0

I'm currently creating a Windows Service and just figured out (thanks to this answer) how to configure the service installer in order to create a custom event log source during installation. As I already figured out by myself, these custom event log sources require elevated privileges to be registered. And that's the reason why the registration happens during installation - because the service installation is always executed with elevated privileges. So far, so good.

However, I'm not 100% satisfied with that solution because, as it is stated in the documentation of ServiceInstaller:

The Log property for this source is set by the ServiceInstaller constructor to the computer's Application log.

And this is not what I want. I want the events to be registered in a custom log called "MyCustomLog". Moreover, I cannot just set my service's ServiceBase.EventLog.Log to "MyCustomLog". How can I individually set my service's EventLog.Log? And where do I have to do this?

As I didn't find an answer for my question yet, I thought of creating a custom view for my service events which should have then looked like below:

enter image description here

It does not replace a custom event log as the events are still registered to the Application log, but it enables me to have an overview of certain events that happened in my service, just like it would be in a custom event log. So, how do I programmatically create such custom views? Is that possible? And if so, where do I need to create them? Does the creation require elevated privileges, so it needs to be done inside the ServiceInstaller? Or could this easily be done inside my service's constructor?

I would appreciate answers concerning the feasibility of both of the approaches!

Pete Hilde
  • 617
  • 8
  • 22
  • IIRC you can derive from ServiceInstaller and clear the Installers collection after your base class constructor has run. You can then add the EventLogInstaller you'd have liked it to add. Only other thing to make sure of is to set the `Source` correctly (because setting it via `ServiceName` on the installer won't work). I could have sworn I wrote an answer on here about doing this years ago but cannot find it. I may have missed a step or two here also, but I know it does work. – Damien_The_Unbeliever Apr 29 '20 at 13:28

1 Answers1

1

More details here. The following should work, minimally, in Visual Studio 2017 and Visual Studio 2019.

  1. In the Solution Explorer of Visual Studio, double-click your service component, i.e., the component that derives from ServiceBase. Doing this will open the component in the [Design] view.
  2. With the [Design] view open, open the Properties grid by pressing F4 (or View|Properties Window from the menu).
  3. In the Properties grid, set the AutoLog property to false. This will prevent events from being written by default to the Windows Application log .
  4. If you have not already done so, right-click anywhere in the [Design] view of the service component, and select the Add Installer menu option. This adds a component to your solution named ProjectInstaller by default.
  5. Note that the new ProjectInstaller is automatically opened to its respective [Design] view. To get to its code, right-click the ProjectInstaller.cs file in the Solution Explorer, and select the View Code menu option.
  6. Change the contents of that file to look like the following. This updates the EventLogInstaller to use the custom log name of your choice.
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Diagnostics;

    namespace YourProjectNamespace
    {
        [RunInstaller(true)]
        public partial class ProjectInstaller : Installer
        {
            public ProjectInstaller()
            {
                InitializeComponent();

                EventLogInstaller installer = FindInstaller(this.Installers);
                if (installer != null)
                {
                    installer.Log = "YourEventLogName"; // enter your event log name here
                }
            }

            private EventLogInstaller FindInstaller(InstallerCollection installers)
            {
                foreach (Installer installer in installers)
                {
                    if (installer is EventLogInstaller)
                    {
                        return (EventLogInstaller)installer;
                    }

                    EventLogInstaller eventLogInstaller = FindInstaller(installer.Installers);
                    if (eventLogInstaller != null)
                    {
                        return eventLogInstaller;
                    }
                }
                return null;
            }
        }
    }
  1. The last step is to tie the service component to the custom event log you named in Step 6. To do that, right-click the service component in the Solution Explorer, and select the View Code menu option. Update the constructor to the following:
    public YourServiceName()
    {
        InitializeComponent();

        // This ties the EventLog member of the ServiceBase base class to the
        // YourEventLogName event log created when the service was installed.
        EventLog.Log = "YourEventLogName";
    }
  1. When you install the service, the YourEventLogName should be created on the system. If the Event Viewer is already open, you'll probably have to refresh it. If it's still not visible, you might need to log something to it (I don't recall the details). In any case, to write log information to the custom event log from your service, use the EventLog member of the service component, e.g.,
    protected override void OnStart(string[] args)
    {
        EventLog.WriteEntry("The service was started successfully.", EventLogEntryType.Information);
    }

    protected override void OnStop()
    {
        EventLog.WriteEntry("The service was stopped successfully.", EventLogEntryType.Information);
    }

    protected override void OnShutdown()
    {
        EventLog.WriteEntry("The service was shutdown successfully", EventLogEntryType.Information);
    }
Matt Davis
  • 44,225
  • 16
  • 92
  • 121
  • I'm following all your steps but unfortunately the events are still written to the Application Log. I even logged the AutoLog as well as the EventLog.Log property values to see if something is configured incorrectly, but AutoLog is set to `false` and EventLog.Log to `MyCustomLog`. I also recreated the windows service project to see if changes that I made maybe affected the use of a custom event log, but that didn't help either. Is there something else I have to consider when configuring the service? – Pete Hilde May 04 '20 at 07:13
  • I figured out that restarting my system makes the events now appear in the log I specified. Is this documented somewhere or did I configure anything incorrectly? If it's documented, I would recommend to add a link to the documentation as well as an annotation to restart the system if the current answer doesn't bring the success that is expected. – Pete Hilde May 04 '20 at 07:28
  • I forgot to mention that I already worked with the EventLog.Source before and now mapped it to a new log, so I had to restart my computer for the changes to take effect as documented here: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.eventlog.source?view=dotnet-plat-ext-3.1 – Pete Hilde May 04 '20 at 07:45