Service installation fails as event source already exists - windows-services

I'm trying to configure a Topshelf-based Windows service to log to a custom event log using Topshelf.Log4Net and log4net. This works fine if I run the application in command-line mode. When I try to install the service with BillsTestService.exe install, I get:
INFO Topshelf v3.1.107.0, .NET Framework v4.0.30319.18052
DEBUG Attempting to install 'BillsTestService'
Running a transacted installation.
...
Service BillsTestService has been successfully installed.
Creating EventLog source BillsTestService in log Application...
An exception occurred during the Install phase.
System.ArgumentException: Source BillsTestService already exists on the local computer.
...
at System.Diagnostics.EventLog.CreateEventSource(EventSourceCreationData sourceData)
I've tried running EventLog.DeleteEventSource("BillsTestService"); in LINQPad before installing; that succeeds, but a subsequent service install still fails.
My log4net appender configuration is:
<appender name="ErrorEventLogAppender" type="log4net.Appender.EventLogAppender" >
<threshold value="ERROR" />
<logName value="MyCompanyServices" />
<applicationName value="BillsTestService" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %logger - %message%newline" />
</layout>
</appender>
What am I doing wrong?
The intent is to have multiple services log errors to the same log name (with different application names); the log would be created by Operations.

Part of the issue is that Topshelf automatically creates an eventlog source named after the service when you install. Since the log4net appender applicationName is also used as an eventlog source, that cannot be the actual application/service name. The source must be unique on the local computer. I added a "Source" suffix to the name in the log4net configuration.
The other part is that the service does not have rights to create the log. It can create a new source, but not a new log. One way to do this is in code (I used LINQPad):
EventLog.CreateEventSource("FOODEBUG", "MyCoSvc");
EventLog mylog = new EventLog("MyCoSvc");
mylog.Source = "FOODEBUG";
mylog.WriteEntry("This is a test.");
EventLog.DeleteEventSource("FOODEBUG");
I'm not positive if you actually have to write to the log to create it; after spending over two days on this, I'd rather be safe.
Also note that log names are limited to 8 characters; you can go longer, but the system only considers the first 8 characters as significant.
There's no need to move the log4net initialization as Chris Patterson suggested. Simply including
configurator.DependsOnEventLog();
configurator.UseLog4Net("MyService.exe.config");
in the HostFactory.Run delegate is sufficient. (I'm using Topshelf.Log4Net.)
Finally, I'm reasonably sure that the entire Windows event logging system is flaky. Event Viewer's refresh doesn't work in all cases, at one point my Application log entries disappeared, and I believe I've seen different results after a reboot.

Move your log4net initialization to the ConstructUsing() configuration delegate for the service instead of specifying for use during install/uninstall which doesn't require the service class to be instantiated.
Or, only use the event log appender when the actual service is running, by either adding the appender outside of the config file or modifying the configuration to eliminate the event log appender unless an ERROR or FATAL event occurs.
My guess is the DEBUG/INFO level events are trying to log to the appender, and the source does not exist yet.

Related

Programmatically change the filename that a Log4j2 RollingFileAppender writes to at runtime

My organization is migrating from Log4j1 to Log4j2. We have a custom rolling file appender that changes the filename that it logs to at runtime when a certain event occurs in the application. This is implemented so that it's easy to find the log file in the log directory. For example the log file directory might look like this;
mylog-2021-08-02.log
mylog-2021-08-03.log
SPECIAL_EVENT_mylog-2021-08-03.log
mylog-2021-08-04.log
mylog-2021-08-05.log
Based on the research I've done it appears that Appender filenames are immutable and I'd have to create a new Appender and add it to the configuration when the event occurs, then when the triggering policy is signaled remove this Appender and add back a new Appender for the original configuration? Is there a more elegant solution than this? Do I need to write a custom appender and handle the file naming/rollover logic myself?
Update 9/2/2021
Thanks for the answer #D.B. this helped me learn quite a bit about Log4j2. The question that you reference is very similar to my situation. We have many devices, and each device needs to log to its own file. I do have some additional requirements though. We have many threads in each device which need to log to the same device log file and many devices that each need their own log file. Additionally, I need to handle the special rollover file naming requirement (original post) when a particular event occurs in the device. Finally, the name assigned to each device is not known until runtime (its defined in another configuration file we have).
I could use markers, like you suggest, but this can quickly become difficult to maintain since developers would need to know they have to pass a marker with every logging statement and the entire existing code base would need to be updated to pass the appropriate marker. I also could use a context map as you suggest but the application has many threads and again developers would need to know they have to set the context data appropriately before logging from any thread.
With Log4j1 these requirements were met by:
A custom appender class derived from RollingFileAppender that handled the special event file naming rollover logic.
A custom filter that accepted events that met the following criteria:
a. The thread name the event came from included “device name” of the device
b. The event message included “device name”
When a new device is instantiated in the system:
a. A new custom filter is created with the “device name” string to filter on.
b. A new custom appender is created that logs to a file named “device name”.log. This appender is created with the custom filter.
c. The appender is added as reference to the Root logger
This results in all log events being sent to the new appender (and every other device appender that is created) but the log events are filter based on the “device name”. This results in a device specific log file.
I could implement a custom filter and appender like we did with Log4j1 but I’d prefer not to be dependent upon the logging core classes. Any additional recommendations you have would be greatly appreciated.
You can achieve it by using ThreadContext.
My configuration file is as following
<Routes pattern="$${ctx:logName}">
<Route>
<RollingRandomAccessFile name="Rolling-Random-Access-File-Appender" fileName="${ctx:logName}.log" filePattern="${ctx:logName}.log.%d{yyyy-MM-dd-hh-mm-ss}.gz">
<PatternLayout pattern="%msg %n"/>
<Policies>
<SizeBasedTriggeringPolicy size="50 MB"/>
</Policies>
</RollingRandomAccessFile>
</Route>
</Routes>
Put some thread context where you write your log like following
ThreadContext.put("logName", fileName);
log4j2logger.log(level, logMessage);

Orleans Error while Initializing Orleans Client

I am getting below error when I try to deploy to the azure. I am doing basic hello world app. Can someone please give some insights. I have attached the logs below.
I am using :: Version 1.1.0-beta2
The silos start properly as per the log files but it cant initialize the Client in azure. I am using the below config file in the Client.
<?xml version="1.0" encoding="utf-8" ?>
<!--
This is a sample client configuration file for use by an Azure web role acting as an Orleans client.
The comments illustrate common customizations.
Elements and attributes with no comments should not usually need to be modified.
For a detailed reference, see "Orleans Configuration Reference.html".
-->
<ClientConfiguration xmlns="urn:orleans">
<!--
To turn tracing off, set DefaultTraceLevel="Off" and have no overrides. To see a minimum of messages, set DefaultTraceLevel="Error".
For the trace log file name, {0} is the silo name and {1} is the current time.
Setting WriteTraces to true will cause detailed performance information to be collected and logged about the individual steps in the
message lifecycle. This may be useful debugging performance issues.
-->
<Tracing DefaultTraceLevel="Off" TraceToConsole="false" TraceToFile="{0}-{1}.log" WriteTraces="false">
<!--
To get more detailed application logging, you can change the TraceLevel attribute value to "Verbose" or "Verbose2".
Depending on the log levels you have used in your code, this will cause additional messages to be written to the log.
-->
<TraceLevelOverride LogPrefix="Application" TraceLevel="Info" />
</Tracing>
</ClientConfiguration>
PS::
I figured it out after enabling the fusion logs. I could see 1 dll was not loaded properly. The issue is fixed.
You should be using AzureClient. It handles all configuration automatically.
Please refer to https://github.com/dotnet/orleans/tree/master/Samples/AzureWebSample and follow the same setup as there. The best way is to close that AzureWebSample and add your own grains and logic.
What version of Orleans are you using? If you included http://www.nuget.org/packages/Microsoft.Orleans.Templates.Interfaces/ in the project, the invoker class should have been generated at compile time. Try cleaning up Properties\orleans.codegen.cs files and rebuilding the project.

Web deployment failing due to file in use

I'm using Microsoft's Web Deploy Remote Agent service to allow me to easily publish code to the server from within Visual Studio.
The web site I am deploying is using log4net to log messages to log files, and every time I try to deploy a new version of the code, I get this error in Visual Studio stating that the current log4net log file is in use:
An error occurred when the request was processed on the remote
computer. The file 'Web.log' is in use.
The process cannot access 'C:\inetpub\wwwroot\Logs\Web.log' because it
is being used by another process.
I can solve this by going onto the server and doing an iisreset before publishing... but that is kind of defeating the point of 'easy' publishing from Visual Studio :)
Is there some way I can get the publish task to issue an iisreset automatically, or some other way I can work round this?
I kept poking around and found some tidbits around the file being locked in a few other forums. Have you tried adding
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
To your <appender> element in the web.config file? From the Apache docs
Opens the file once for each AcquireLock/ReleaseLock cycle,
thus holding the lock for the minimal amount of time. This method of
locking is considerably slower than FileAppender.ExclusiveLock but
allows other processes to move/delete the log file whilst logging
continues.
As far as the performance considerations, I suppose you would need to test if this will affect you or not as I am assuming it really depends on how often you are writing to the log file as to how much this will impact performance. I can't believe that getting/releasing a lock could take all that much time though.
There is a MSDEPLOY provider called recycleApp which is used exactly for this. You can include this in your deployment manifest.
Another option is to use ignoreOnErrors flag which will skip the file in use and continue with the deployment.

Rename Web Role in VS 2010 Cloud Service Project

I just started using VS 2010 to create a Cloud Service (HealthTracker), and I attached a MVC2 web project to it. When I hit Debug, the dev fabric was started and I was able to navigate my web app on my machine as expected.
I decided MVCWebRole2 was a bad name for my web app, so I renamed it to HealthTrackerMVC. I used Refactor --> Rename to change MVCWebRole2 to HealthTrackerMVC. I Built clean and now when I hit debug the dev fabric starts, and the web app never starts and eventually it exits debug mode without me doing anything.
How do I fix this? I'd rather not start over with everything...
UPDATE
I have checked the ServiceConfiguration.cscfg, the ServiceDefinition.csdef and the solution file. All the names match, and all the GUIDs match. I even renamed the folder that housed HealthTrackerMVC (formerly named MVCWebRole2) and edited the solution file to point to the new project. Everything loads and builds correctly. The Development Fabric shows HealthTrackerMVC starting, says it's busy, then shuts it down, rather quickly. See the attached screenshot:
So I know my web role is being started... why is it shutting down so quickly?
Check the Azure configuration files, as both reference the role name and I don't belive VS's refactor command hits. If your project is building and the role simply isn't launching, its most likely as a result of the role not knowing what to start.
In ServiceDefinition.csdef
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="YourAzureService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="HealthTrackerMVC" vmsize="Small" enableNativeCodeExecution="true">
...
In ServiceConfiguration.cscfg
<?xml version="1.0"?>
<ServiceConfiguration serviceName="YourAzureService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
<Role name="HealthTrackerMVC">
...
If that doesn't work, right click on "Roles" under the Cloud Service Project in Solution Explorer. The ADD menu should have an option for "Web Role Project in Solution". Select that and link up your new role. Delete the old role as well at this point
If that still doesn't work, go to the file system where the project is stored and open the .ccproj file (Cloud Service Project) in a text editor.
Look for the reference to the previous role (ccproj are in MSBUILD format). It will be something like:
<ItemGroup>
<ProjectReference Include="Folder\MVCWebRole2.csproj">
<Name>YourAzureService</Name>
<Project>{26f72b59-1423-4175-b401-9c8f5f45db2a}</Project>
<Private>True</Private>
<RoleType>Web</RoleType>
<RoleName>MVCWebRole2</RoleName>
</ProjectReference>
</ItemGroup>
Change references to the new HealthTrackerMVC project (name and .csproj ref) and you should be good to go. Most likely the project GUID hasn't changed, but if somehow it did, just open up the SLN file to get that number.
Once you change on this VS should prompt to reload the Solution/Projects. If not, you should reload anyways.
I recommend to check Web.config and the actual start-up logic (i.e. Azure fabric is known to silently kill web projects with invalid web config without raising any errors; that's something that just made my life exciting a few times).
Just some ideas. For example you can try by starting web project alone (just like a usual project). If it works - drop an existing web role and add a new one to the solution (referencing this web project) and try running it in the dev fabric. If it does not, but web project runs alone - export it to a fresh solution and add to a new web role there.
This is a bit of a long shot, but if you have overwritten the RoleEntryPoint and overwritten the Run method, it should contain something like
public override void Run()
{
while (true)
{
Thread.Sleep(8000);
}
}
If this method ever returns, your application will stop.

AppFabric Cache Error:The AppFabric Caching Service service terminated unexpectedly

I am running cluster machine in Virtual Box in domain, by default service is running under Network service , service stopped all the time with the following error in the event log.
please find the error details from error log below. any help will be great.
Log Name: System
Source: Service Control Manager
Date: 21-07-2010 16:42:07
Event ID: 7034
Task Category: None
Level: Error
Keywords: Classic
User: N/A
Computer:
Description:
The AppFabric Caching Service service terminated unexpectedly. It has done this 5 time(s).
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Service Control Manager" Guid="{555908D1-A6D7-4695-8E1E-26931D2012F4}" EventSourceName="Service Control Manager" />
<EventID Qualifiers="49152">7034</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2010-07-21T14:42:07.000Z" />
<EventRecordID>13342</EventRecordID>
<Correlation />
<Execution ProcessID="0" ThreadID="0" />
<Channel>System</Channel>
<Computer>
<Security />
</System>
<EventData>
<Data Name="param1">AppFabric Caching Service</Data>
<Data Name="param2">5</Data>
</EventData>
</Event>
thanks for the support.
kazim
There is no much information in the above error to guess what went wrong. Try to take a look at events right before this particular event (maybe there will be hint/warning about something). Another thing might be not to look only at a regular eventlog Windows Logs > Application but also at eventlog Applications and Services Logs > Microsoft > Application Server-System Services.
[Resolved]
I got the same issue. Couldn't find a definite answer anywhere. However after looking at all the configurations and connections, I figured out the root cause.
For information, in my case, I was using a SQL Configuration.
The issue was that my AppFabric database was not part of a cluster and availability group which it should have been actually. Once I added it to the availability group and after it got replicated in all the SQL nodes, I re-configured app fabric on the cache servers (using configure app fabric tool) and stopped and started my cache cluster again.
This time, everything worked as expected.
Hope this helps you too!
P.S.: I'm not sure if the "reconfiguring app fabric using the tool" is a mandatory step. I just did it from my side. Perhaps you can try stopping and starting the cache cluster without doing this. Do let me know in case it is not mandatory so that I can update this answer accordingly.
Agreed with David that there is not much one could make out of this log entry.
Another thing worth checking would be to make sure that your configuration is available to AppFabric services. May it be an xml or SQL based configuration provider, AppFabric services should be able to access it. This is the most common reason of crashing services at the load time.
You can very easily check this by running your appFabric configuration wizard.

Resources