I'm trying to get my .Net Windows Service to right to a custom event log. I'm using EventLogInstaller to create the event log and source when the application is installed. I read here that it takes a while for Windows to register the source so they reccomend you restart the application before trying to write to the log.
As this is a Windows Service I didn't want to have to force a computer restart or get the user to manually start the service up, so I use this code to wait for the log to exist and then start the service automatically.
while (!(EventLog.Exists("ManageIT") || EventLog.SourceExists("ManageIT Client Service")))
{
Thread.Sleep(1000);
}
System.ServiceProcess.ServiceController controller = new System.ServiceProcess.ServiceController("ManageIT.Client.Service");
controller.Start();
My problem is that events from the service are still written to the Application Log and although I can see my custom log in the Registry Editor it does not show up in the Windows 7 Event Viewer.
Any help will be much appreciated.
By default when a service is installed, the source gets associated with the Application Log.
If we change this association at a later point, the system needs a restart.
We can however prevent the association of the service with the application log, by setting autolog property to false in the service class (class which inherits from servicebase) constructor.
http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.autolog.aspx
Try this snippet:
edit - caveat: if the user running the code does not have administrator rights, this will throw an exception. Since this is the case (and if the user will not have these rights) best practices should be to assume the log exists, and simply write to it. see: The source was not found, but some or all event logs could not be searched
if (!EventLog.SourceExists("MyApplicationEventLog"))
{
EventSourceCreationData eventSourceData = new EventSourceCreationData("MyApplicationEventLog", "MyApplicationEventLog");
EventLog.CreateEventSource(eventSourceData);
}
using (EventLog myLogger = new EventLog("MyApplicationEventLog", ".", "MyApplicationEventLog"))
{
myLogger.WriteEntry("Error message", EventLogEntryType.Error);
myLogger.WriteEntry("Info message", EventLogEntryType.Information);
}
It sounds like you are writing to the event log like this:
EventLog.WriteEntry("Source", "Message");
This will write to the application log.
If you use the code in simons post with the creation of myLogger, you can specify the name of the Log.
I did something like this:
var logName = EventLog.LogNameFromSourceName("MyApp", Environment.MachineName);
//delete the source if it associated with the wrong Log
if (!string.IsNullOrEmpty(logName) & logName != "MyLog")
{
EventLog.DeleteEventSource("MyApp", Environment.MachineName);
}
if (!EventLog.SourceExists("MyApp"))
{
EventLog.CreateEventSource("MyApp", "MyLog");
}
Related
As the title suggested, is it possible to print out info for web API? I understand there is the option of logging but I am just trying to look for a simple print. I tried console.writeline() but my WEB API do not have a console.
I publish the API to an IIS server, and I would call the API for various functions through a webpage. However, there is no logging setup yet therefore I am trying to find a quick and easy way to print info such as the value of a variable etc. For instance, I would console.log() when I do a quick troubleshoot on my webpage, how can I achieve this for WEB API?
There are a couple of options.
If you use a typical logging framework like Log4Net or Serilog or similar, you can easily write to files. This is easy to set up and recommended.
If you need it now, and are using windows, you could use the event log to write data to it.
See: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.eventlog?view=dotnet-plat-ext-6.0
// Create an EventLog instance and assign its source.
EventLog myLog = new EventLog();
myLog.Source = "MySource";
// Write an informational entry to the event log.
myLog.WriteEntry("Writing to event log.");
And look for it in the windows event log.
See this on how to access it.
I just noticed writing to a txtfile would be the easiest for me, if I were to avoid setting up logging, basically I will just call as something below when needed.
private void fakeLogging (string data)
{
string logpath = #"C:\path\to\file.txt";
if (!System.IO.File.Exists(logpath))
{
FileStream fs = System.IO.File.Create(logpath);
fs.Close();
}
System.IO.File.AppendAllText(logpath, DateTime.Now + " " + data + Environment.NewLine);
}
I have created a simple Windows service, following these youtube videos:
https://www.youtube.com/watch?v=cp2aFNtcZfk.
This works, so long as I don't try to do any logging. If I call my logging function:
public static void LogMsg(LogMsgTypes msgType, string msg)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
string logFileName = string.Format("{0}Recalculator{1:yyyyMMdd}.log",path, DateTime.Now);
var file = System.IO.File.AppendText(logFileName);
file.WriteLine(string.Format("{0} {1,-9} : {2}", DateTime.Now.ToString(), msgType, msg));
file.Close();
}
then the service crashes and I get an Unauthorized Access Exception error in the Windows Event Log. I know I should be logging to the Event Log anyway, but I gather I will have to create the source manually first and I would really like to be able to write to a file if possible. On the youtube tutorial I am following, the guy gets no errors at all.
I think the correct answer is probably that I should do it 'right' by creating a source in the Windows Event Log and then writing to there instead of to a custom log file.
For now, I have just installed the service to run under Local System.
I have been fighting with the Windows Event log for lots of hours with inconsistent behaviour during test of the log4net EventLogAppender and I realized, that the log4net code worked, but my windows event log was the one being unreasonable.
System
OS: Windows 8.1
C#: .Net 4.5, built to x64
Creating the error case
C#: Create Source1 in TestLog1
C#: Write to the log (Works)
Powershell: Removing the log using powershell
C# Create Source1 in TestLog2 (Different log)
C# Write to the log <= This shows no log entries in TestLog2!
I have made a complete step-by-step guide to recreate the problem:
1: Create a new source in a new log and write to it
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog1");
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
List logs using powershell-command:
Get-EventLog -LogName *
This will correctly list all logs, including TestLog1 containing 1 log entry.
I can also get the log entries by using this powershell command:
GetEventLog -LogName "TestLog1"
This shows me the single log message in the log.
2: Delete the event log using powershell
Powershell command:
Remove-EventLog -LogName "TestLog1"
Listing all logs now shows, that the log has actually been deleted. Powershell command again:
Get-EventLog -LogName *
3: Create the source again, but in another log this time
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog2"); // New log name
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
Result:
The log appears in powershell when listing all logs
The log does not contain any entry
Using Get-EventLog "TestLog2" throws and exception even though it appears in the log-list
Deleting the log in powershell using remove-eventlog -logName "TestLog2" somehow still works.
It seems that in some cases, the logs seems to exist, but in others it doesnt.
A: Is this a known bug or what is wrong with my scenario?
B: How can I clean up my existing mess if sources somehow still exist pointing at the old log? (If thats the case, that is)
EDIT: I even tried the following C# code to delete the source first and then the log, but the result is the same:
var source = "TestSource6";
var logName1 = "Testlog5";
var logName2 = "Testlog6";
EventLog.CreateEventSource(source: source, logName: logName1);
new EventLog() { Source = source }.WriteEntry("This is a message in log " + logName1);
EventLog.DeleteEventSource(source:source);
EventLog.Delete(logName:logName1);
EventLog.CreateEventSource(source: source, logName: logName2);
new EventLog() { Source = source }.WriteEntry("This is a message" + logName2);
Unfortunately you can't re-register an event source "back to back". It's one of the (many) reasons installers often ask to restart the computer.
From MSDN:
If a source has already been mapped to a log and you remap it to a new log, you must restart the computer for the changes to take effect.
EventLog.CreateEventSource Method (String, String)
For fixing the issue, I would recommend not deleting the event source unless the product is uninstalled. Just stop using Log1 and start using Log2, without deleting and recreating. When you go to use any log, you could use something similar to this:
if (!EventLog.SourceExists(source, log))
{
EventLog.CreateSource(source, log)
}
And simply leave the source where it is, until you uninstall the product. If you're using InstallShield, it should automatically detect a restart is required and ask the user to do so.
Take the following C# code:
EventLog[] eventLogs;
eventLogs = EventLog.GetEventLogs(computername);
foreach (EventLog evt in eventLogs)
{
statusMessagesListBox.Items.Add("evt.Log.ToString(): " + evt.Log.ToString() + "\t\tevt.LogDisplayName: " + evt.LogDisplayName);
}
When I run that, my output looks like this:
evt.Log.ToString(): Application evt.LogDisplayName: Application
evt.Log.ToString(): HardwareEvents evt.LogDisplayName: Hardware Events
evt.Log.ToString(): Security evt.LogDisplayName: Security
And so on, like that. But why is there no Setup log? Furthermore, when I attempt to run this code:
var eventLog = new EventLog("Setup", computer);
eventLog.Clear();
eventLog.Dispose();
I get an error message that the log 'Setup' does not exist on that computer, even though it definitely does. The above code works for all other event logs except the Setup log.
How do I access the Setup event log?
For reference, the .NET frameworks being tried are 4.0 and 4.5, and the target computers are Windows 7 and 2008 R2.
The EventLog class only deals with Administrative event logs. The SetUp event log is an Operational log (you can see this in Event Viewer), so cannot be dealt with by this class.
To access the SetUp event log, you have to use the classes in the System.Diagnostics.Eventing.Reader namespace. You can iterate through the events using:
EventLogQuery query = new EventLogQuery("SetUp", PathType.LogName);
query.ReverseDirection = true; // this tells it to start with newest first
EventLogReader reader = new EventLogReader(query);
EventRecord eventRecord;
while ((eventRecord = reader.ReadEvent()) != null)
{
// each eventRecord is an item from the event log
}
Take a look at this MDSN article for more detailed examples.
I need to check if a user has write permissions for the event log. My solution right now is to write a test message in the log and delete it afterwards (so that the log does not get messed up, as the check for permissions is called often (every 3-5 Mins.) by some 'Healthcheck'-service:
const string log = "MyApplicationLog";
const string source = "PermissionCheck";
EventLog evLog;
try
{
if (!EventLog.SourceExists(source))
{
EventLog.CreateEventSource(source, log);
}
evLog = new EventLog();
evLog.Source = source;
evLog.WriteEntry("PermissionCheck Test Message");
return true;
}
finally
{
//remove the check messages:
if (EventLog.Exists(log))
{
EventLog.Delete(log);
}
}
Is there any possibility to check the permissions without actually writing a log entry?
Thank you in advance,
ElKunzo
Yes, AFAIK, using CAS. Decorate the required member/s with the EventLogPermission attribute, from there you can control whether you must have access, only desired and so forth.
This may well entail a little further adventure in CAS itself, however, if you're unfamiliar.
MSDN Link.