logging to a text file in high demand environment

K

kpg

Hi all,

I have a vb asp.net web service where I log user activity to a
text file like this:


Using sw As StreamWriter = New StreamWriter(file, True)
sw.WriteLine(data)
sw.Flush()
sw.Close()
End Using


I'm using the 'using' block becuase after reading about it, it
seems like a good idea to ensure resources are released properly.

Question:

When the web service is called simultaneously by several users do
I need to worry about the file being inaccessible because another
process is writing to it?

If so, what is the best way to do this? In a Try..catch I would assume,
perhaps this:


Try
Using sw As StreamWriter = New StreamWriter(file, True)
sw.WriteLine(data)
sw.Flush()
sw.Close()
End Using
Catch ex as exception
'??? - wait for a few milliseconds and retry?
'give up after several attempts???
End Try

Ideally I would like to 'never give up' but then again I don't want a
race condition either.


Thanks,
kpg
 
M

Martin

Hi all,

I have a vb asp.net web service where I log user activity to a
text file like this:

Using sw As StreamWriter = New StreamWriter(file, True)
  sw.WriteLine(data)
  sw.Flush()
  sw.Close()
End Using

I'm using the 'using' block becuase after reading about it, it
seems like a good idea to ensure resources are released properly.

Question:

When the web service is called simultaneously by several users do
I need to worry about the file being inaccessible because another
process is writing to it?

If so, what is the best way to do this?  In a Try..catch I would assume,
perhaps this:

Try
  Using sw As StreamWriter = New StreamWriter(file, True)
    sw.WriteLine(data)
    sw.Flush()
    sw.Close()
  End Using
Catch ex as exception
  '??? - wait for a few milliseconds and retry?
  'give up after several attempts???
End Try

Ideally I would like to 'never give up' but then again I don't want a
race condition either.

Thanks,
kpg

You could look at using a Mutex object (in the System.Threading
namespace). These are essentially mutually exclusive objects that can
control access to shared resources.

Declare the mutex object as private and shared in the declarations
section of your class:

Private Shared ThreadLock as new Mutex()

Then, in the actual routine you would put something like the
following:

dim sw as StreamWriter
try


if Threadlock.WaitOne() Then
sw = New StreamWriter(file, True)
sw.WriteLine(data)
sw.Flush()
End if

catch ex as exception

finally
'Close the stream writer
If not sw is nothing then sw.Close
'always call the release method, otherwise the mutex will be held in
a locked state
Threadlock.ReleaseMutex()
end try

I've left the Try-Catch block, as whenever you do IO operations, you
should always anticipate an error.

I've also added a Finally block. This will ensure that the code in
this section is always executed.

Hope this helps...

Martin
 
K

kpg

That sounds good. The mutex is declared as shared (which is
static) so it exists independent of an instance of the class.

Does the thread pooling method specified in IIS effect the scope
(may not be the right word) of the mutex?

I'm confused as to how several other users on the system, using
the web service (and the class) will be using the same mutex
when that mutex was not given an explicit name. I see that the
mutex, being shared, has only one copy that exists for all
instances of the class.

I may have just answered my question

Maybe I'm confusing IIS 5.0 thread pooling with IIS 6.0,
In 5.0 there was a thread pool setting that ran everything in
a different thread (isolated, I think). In 6.0 that seems to
have changed. I specify different thread pools for different
types of services. But of course this particular service will
run in its assigned pool, so again I guess it works as you
described - not that the thread pool setting would effect this
anyway, now that I think about it.

cool.

thanks,
kpg
 
K

kpg


seems like such a simple concept...

I do this:


Dim myTraceLog As New System.IO.FileStream(sLogFile, _
IO.FileMode.OpenOrCreate)

Dim myListener As New TextWriterTraceListener(myTraceLog)

Trace.WriteLine(Now.ToShortTimeString & "," & data)


....but the Trace statement is never run. That is, it's like its
commented out - the compiler is not seeing it.

I'm running a web service, does that matter?
 
M

Mick Wilson

...but the Trace statement is never run.

You're almost there. You need to add the listener object to the
collection:

Trace.Listeners.Add(myListener)
 
G

George Ter-Saakov

I believe that you can not log into text file in high demand environment...
Writing to file does not support multithreaded access.... You will mess-up
your log file if you try to write in it from different threads
simultaneously.

documentation says about TextWriterTraceListener "Any instance members are
not guaranteed to be thread safe. "


George
 
M

Mick Wilson

documentation says about TextWriterTraceListener "Any instance members are
not guaranteed to be thread safe. "

Does that matter if all of the write activities go through the thread-
safe Trace class methods? You may be right about the disk contention
issues, but I'm curious about what you mentioned with regard to the
TextWriterTraceListener itself because I don't have a lot of
experience dealing with concurrency issues.

Thanks,
Mick
 
K

kpg

Thanks for the input.

Here's what I ended up with. As usual, when I spend too much
time on a piece of code I start embellishing it and have to
stop myself.

The reason I broke out WriteTofile is that I also write data
dumps to a unique filename that will never be in use, so why
go through the trouble of 'locking' it, plus I needed it in
the exception handler for AbandonedMutexException.

WriteToLog builds my date-based file name (simplified here),
then calls the protected WriteToSharedFile routine.

I added a handler and log entry for the AbandonedMutexException,
knowing that if I'm writing to a 'shared' file it must be the
log file. Works for me in this case.

ASP.NET 2.0 documentation says the thread receiving the
AbandonedMutexException now owns the mutex so I can proceed.

I contemplated adding a timeout to the WaitOne, say 1000, but
was not sure how to set the 2nd Boolean argument, plus if it's
locked for that long there must be a problem. Not sure how
likly that is.


Sub WriteToLog(ByVal data As String)
Dim sLogFile As String = "c:\path\myfile.log"
WriteToSharedFile(sLogFile, data)
End Sub

Sub WriteToSharedFile(ByVal file As String, ByVal data As String)
Try
If ThreadLock.WaitOne() Then
WriteToFile(file, data)
End If
Catch ex As AbandonedMutexException
WriteToFile(file, "AbandonedMutexException")
WriteToFile(file, data)
Catch ex As Exception
Finally
ThreadLock.ReleaseMutex()
End Try
End Sub

Sub WriteToFile(ByVal file As String, ByVal data As String)
Dim sw As StreamWriter
Try
sw = New StreamWriter(file, True)
sw.WriteLine(data)
sw.Flush()
Catch ex As Exception
Finally
If Not sw Is Nothing Then sw.Close()
End Try
End Sub

kpg
 
G

George Ter-Saakov

If Trace is Thread safe you should be ok......
Apparently it prevents multiple threads from writing at the same time but
then it contradict to "high demand environment"

----------------------------------------------------------------------

Somehow I did not think that they (Microsoft) make Trace a thread safe. I
kind of expected that underlying writer will have to take care of thread
safety.. .What if I am logging into database then I have unnecessary
contention in Trace class since it's still going to prevent multiple threads
from writing at the same time......

---------------------------------------
Actually I always used MS Sql for logging. But it's just because I have not
written application that is not using DB for years....

George.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top