tags:

views:

585

answers:

7

I'm trying to add a log monitor to an in-house test utility for a windows service I'm working on. The service is written in C++ (win32) and the utility is in .NET (C#)

The log monitor works for many other C++ apps I've written, but not for my service.

The only main difference I can see is that the other apps use the older ::WriteFile() to output to the log, whereas in the service I'm using std::ofstream like this:

std::ofstream logFile;
logFile.open("C:\\mylog.log");
logFile << "Hello World!" << std::endl;
logFile.flush();

From my utility I use FileSystemWatcher like this:

FileSystemWatcher fsw = new FileSystemWatcher(@"C:\", "mylog.log");
fsw.Changed += new FileSystemEventHandler(fsw_Handler);
fsw.EnableRaisingEvents = true;

But for the service, it never gets any change events as the log is updated. I've found that any example code using FileSystemWatcher I've come across online has the same exact issue as well... But, I know the events should be available because other log monitor apps (like BareTail) work fine with the service log file.

I'd rather get the C# code for the utility to just work so it works with anything, but if I have to change the logging code for the service I will. Does anyone see what's going wrong here?

+1  A: 

Does it work if you run your service as a plain old exe? Could this be a user account issue?

Assaf Lavie
Not sure...the service won't run by itself without a lot of modification, so I'd be hard to test. Though "Interact With Desktop" is enabled on the service... Also, BareTail updates the log just fine...granted, it's probably written in C...but still...
Adam Haile
+3  A: 

Just a wild guess, but does the utility fire when the service actually closes the log file? The reason I ask is that Windows might not be updating the file metadata on calls to std::ofstream::flush() -- which also sometimes happens in some virtual filesystem implementations in other operating systems.

I'll also check whether the utility has the appropriate permissions to access to the log file created by the service. If you're running the service as an administrator you might have to run the utility as the same user.

Dean Michael
Oddly enough, that's all I get. I get a changed event when it opens the file, then again when it closes. Just to check and Process Monitor (sysinternals) does pick up on the WriteFile operations... so I know I SHOULD be able to see them....
Adam Haile
+2  A: 

Two ideas:

First, make sure your FileSystemWatcher is running with full trust. Try setting this on the method where you initialize the watcher:

[PermissionSet(SecurityAction.Demand, Name="FullTrust")]

For an example, see the FileSystemWatcher.Filter sample code on MSDN.

If that doesn't work, try opening the file using:

std::ofstream logFile;
logFile.open("C:\\mylog.log", ios::out, filebuf::sh_read);

It may be that you're locking the file, which is (for some reason) preventing the file system watcher from seeing the changes to the file on your write.

Reed Copsey
Is there a namespace you have to specify for filebuf::sh_read ?, I get this on compile: error C2039: 'sh_read' : is not a member of 'std::basic_filebuf<_Elem,_Traits>'
Adam Haile
If you're on windows, I believe you can include "fstream.h" (vs <fstream>) and get this to work. It's not part of the std c++ libs, though, since it's somewhat related to windows file system calls.
Reed Copsey
No go on "fstream.h" says it can't find that file.
Adam Haile
+3  A: 

Have you tried setting

        fsw.NotifyFilter = NotifyFilters.LastWrite;

or other filters?

AppDeveloper
A: 

I really wanted to be able to pick one of the previous answers as "the answer", but all of them contributed to me being able to figure out the final solution.

After a great deal of trial and error with each solution, I found that I could get it to work (without modifying the C++ logging code) by setting NotifyFilter to:

NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.CreationTime;

I had kind of assumed that by default it would've searched for everything by default, but obviously not. In general, I think the filter that helped it the most was "Size". LastAccess worked better, but it didn't always pick up every change... it kind of depended on when the watcher was launch. But Size got it to see all changes.

Thanks for all your help everyone! Since I couldn't pick just one answer I tried to be fair and made sure to up-vote each one of your answers.

Adam Haile
Not fair :) my answer was the closest since it was the filters that caused the problems and found you the solution :).. Great that you got it working though
AppDeveloper
A: 

I'm having the same problem. I created an app that's the equivalent of the UNIX tail application. The app used to work find when using it to view .NET trace log files generated by an ASP.NET web app running in IIS. It worked fine under Server 2003. But, now in Server 2008 and Windows 7, something seems to have changed and it's not detecting changes. I think something changed in Windows, maybe something having to do with file buffering or what not. What's odd is that the tail.exe that comes with the Windows Resource Kit works. I'm wondering if maybe it isn't just polling the file at an interval of a quarter second or something.

Jon
A: 

I solved the problem by setting the IncludeSubdirectories to 'true'.

The directory I watch doesn't have any subdirectories, yet that solved the problem...

werner