0

Objective

Use System.Diagnostics to perform tracing. Though I have used log4net and other logging solutions, I am only interested in getting tracing to work with System.Diagnostics.

Problem

Even though I'm issuing the TraceEvent the file is not being created anywhere.

Application Information

I have an application that's hosting some WF services. One of the services is a state machine with an initial state that looks like this:

State Machine Initial State

the LogMessage custom activity is also very straight forward. It receives four basic parameters:

LogMessage Parameters

defines the TraceSource as a variable:

LogMessage TraceSource Variable

and then simply calls TraceEvent:

LogMessage TraceEvent Invocation

Configuration

The configuration for this TraceSource and TraceListener is as follows:

  <system.diagnostics>
    <trace autoflush="true"/>
    <sources>
      <source name="log" switchValue="All">
        <listeners>
          <add name="file" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
               BaseFileName="gsf_workflows.txt"
               DiskSpaceExhaustedBehavior="ThrowException"
               Location="Custom"
               CustomLocation="D:\Log"
               MaxFileSize="81920000"
               LogFileCreationSchedule="LogFileCreationScheduleOption.Daily"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
Community
  • 1
  • 1
Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232

2 Answers2

10

FYI for everyone stumbling on this page..

FileLogTraceListener will not create folders if they are missing.

FileLogTraceListener will not bypass security, your process identity will need create+modify permissions on the target folder.

It's "bad form" to target the executable folder, this tends to change depending on the host (for example, when writing under IIS Express you aren't writing to the same location as DevEnv, nor the hosted web app.) One suggestion is that instead of "ExecutableLocation" you may want to opt for "Custom" and specify a particular path (such as X:\logfiles)

Writers flush to disk when their internal buffers fill, if memory serves me the default buffer size is 8KB. This is not a facet of trace listeners, but the underlying file stream it writes to.

Lastly, if you do not need the form and function of FileLogTraceListener, instead consider tracing to the EventLog (there is a listener for this) as this may be more accessible to other devs and non-devs (such as ops engineers, third party monitoring tools, etc.)

Shaun Wilson
  • 8,727
  • 3
  • 50
  • 48
  • 1
    Thanks for all the advice. In my current situation I'm running under IIS Express in Debug so it's running under my account and thus has all rights to the output folder (see my update I'm also now using a custom folder based off of feedback). However, I do in fact need the form and function of that listener because it rolls over logs and we do 100s of 1000s of transactions every day. – Mike Perrenoud Jan 25 '13 at 18:54
  • I believe log4net has adapters so that it can function as a trace listener. I mention it because you may be familiar, and because in my own experience the in-built filelogtracelistener (among others) will experience performance problems under extreme load (in terms of bus i/o and disk/thread contention, resource utilization, etc). It blocks writers with a lock/Cs/Monitor (and, thus, it writes loglines out-of-order cross-thread), it doesn't overlap writes, it holds a lock during file rollovers. In effect FileLogTraceListener is a process-wide, non-order-preserving, disk bound shared lock. – Shaun Wilson Jan 26 '13 at 19:48
  • For reference; I've maintained and implemented systems that handled 8-40k requests/sec sustained and a poor choice in logging provider can quickly murder a high-load system. I still use it despite having been griefed by it so many times since 99% of the systems out there barely do 1000 requests/sec burst, and I prefer the .NET Tracing framework. If you stick with the in-built listener my suggestion is you reflect the source code, copy it, paste it into a new source file and use your self-compiled version instead. You should expect to need to modify it at some point down the road. – Shaun Wilson Jan 26 '13 at 19:50
  • @ShaunWilson You are a godsend --either the doc doesn't mention or I didn't see that you have to flush the writer to make it actually write to disk. – Michael McPherson Aug 06 '15 at 15:04
  • @ShaunWilson Custom listener does not create a log file for initializeData="CustomWeblog.txt", but initializeData="d:\CustomWeblog.txt" triggers log file creation. What can be the reason: http://stackoverflow.com/questions/35821407/tracesource-custom-listener-does-not-create-a-log-file-for-relative-path-but-wo – Anton Lyhin Mar 06 '16 at 09:18
  • 1
    @Spirit - `InitializeData` property is not something you should need to use with `FileLogTraceListener` (this differs from your linked question, which uses a different TraceListener class), `FileLogTraceListener` would instead use use `BaseFileName="CustomWeblog.txt"`, `Location="Custom"` and `CustomLocation="D:\"` --- it's worth noting by default if you do not specify a path "current working directory" is used, perhaps your log files are created in the CWD for iisexpress (or etc) and not where you would expect them to be created. – Shaun Wilson Mar 13 '16 at 04:46
3

Two things:

1) Your workflow is most likely stopping due to exceptions because your .config file is not right. Note the changes:

<system.diagnostics>
  <sources>
    <source name="log" switchValue="All">
      <listeners>
        <add name="file" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, 
                         Microsoft.VisualBasic, Version=10.0.0.0, 
                         Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             BaseFileName="gsf_workflows.txt"
             DiskSpaceExhaustedBehavior="ThrowException"
             Location="ExecutableDirectory"
             MaxFileSize="81920000"
             LogFileCreationSchedule="Daily"/>
      </listeners>
    </source>
  </sources>
</system.diagnostics>

2) You've to flush the listeners, otherwise they won't be written. You can do it in two ways.

Explicitly call Flush method on your logger variable using again InvokeMethod activity.

OR

Turn on auto flush on config file:

<system.diagnostics>
    <trace autoflush="true"/>
    ....
</system.diagnostics>

That being said, I don't know if you're aware of Workflow Tracking and Tracing capabilities. It looks a good fit for your needs. Check this answer for more links and examples.

Community
  • 1
  • 1
Joao
  • 7,366
  • 4
  • 32
  • 48
  • As an aside, it should not be necessary to use a full name (Version, Culture, token, etc) a partial name is sufficient. Although the location, schedule and options derive from Enums internally, if you look at the code the interpretation of the config section is by string matching exclusively. This is why using fully qualified names for creation schedule and location would not be working as expected. – Shaun Wilson Jan 24 '13 at 22:46
  • Thanks for the answer friend, and I didn't include the `autoFlush` because in PROD I don't want to `autoFlush`. However, even after adding the `autoFlush` and modifying the *.config* file as you stated it still doesn't work. FYI, I did go ahead and go with a custom folder like you said too. – Mike Perrenoud Jan 25 '13 at 18:51