saTrilogy.Etw

The saTrilogy.Etw class library exposes a managed, safe F# implementation of an EventSource via the use of the Microsoft® Microsoft.Diagnostics.Tracing.EventSource NuGet Version 1.0.26 package (although it does work with 1.1.13-beta – the non-beta version is used to permit simple NuGet installation). The solution was developed using the Microsoft Visual Studio Ultimate 2015 Preview (VS2015) IDE against the Version 4.5.53349 .NET Framework and all projects are coded using F# Version 4.0 with FSharp.Core Version 4.4.0.0 (note this impacts the Swenson Unquote module usage requirement).


Keywords
ETW, Localisation, Tracing, Assertion, F#, Swenson.Unquote, Logging, EventSource
License
Unlicense
Install
Install-Package saTrilogy.Etw -Version 1.0.5487

Documentation

F# ETW EventSource

Overview

Read the Getting started tutorial to learn more.

GitHub Pages: http://saTrilogy.github.io/saTrilogy.Etw/index.html

The class library is also available via NuGet; you should download it from GitHub and make changes that are appropriate to your usage of an EventSource such as...

  • The EventSource Name

  • Your preferred enumerations for Process and Undertaking keywords

  • Any changes or additions to the ETW-based RESX localisation

NuGet Package

The EventSource component of the project is available via Nuget at saTrilogy.Etw - F# ETW EventSource

It can be installed vis a NuGet search on saTrilogy.Etw or via the Packagae Manager console using Install-Package saTrilogy.Etw

What follows is the Summary from the PDF documentation...

The saTrilogy.Etw class library exposes a managed, safe F# implementation of an EventSource via the use of the Microsoft® Microsoft.Diagnostics.Tracing.EventSource NuGet Version 1.0.26 package (although it does work with 1.1.13-beta – the non-beta version is used to permit simple NuGet installation). The solution was developed using the Microsoft Visual Studio Ultimate 2015 Preview (VS2015) IDE against the Version 4.5.53349 .NET Framework and all projects are coded using F# Version 4.0 with FSharp.Core Version 4.4.0.0 (note this impacts the Swenson Unquote module usage requirement).

Since VS2015 incorporates a built-in Unit Testing Framework using the .NET Extension Microsoft.VisualStudio.QualityTools.UnitTestFramework (Version 10.1.0.0 with file version 14.0.223101) this methodology was used to develop Test Methods within the solution.

Assertion event methods make use of the test member of the Swenson Unquote package; the package is also used to provide a qprint function to "stringify" class (or other) member values into a single, easily-readable string for appending data to event Write methods where required and this is backed up, if required, by an extension to System.Array for concatenation of a number of qprint and/or other outputs. Both qprint and assertion testing make extensive use of F# quotations; the Swenson Unquote module provides a complete expression parser that permits a wide scope of quotation handling for event tracing. This approach was undertaken primarily because it bypassed the need to decorate code with attributes or import additional libraries for the serialisation of a class or other members.

I have been unable to successfully run (as opposed to compile) an F# project that makes use of EventSource Keywords (and Tasks and, probably, Opcodes) since, at runtime I always received an Out of Band exception that referenced Keyword values were undeclared. Consequently, the methods in this EventSource make no use of Keywords, Tasks and Opcodes; it does, however, successfully make use of the pre-defined Channels and Event Levels.

Every EventSource method has, as a primary argument, the invoker of the tracing call. I have incorporated a Reflector.Invoker static method that successfully uses the [<CallerMemberName>] attribute to return such. In F# this is returned as an expression that incorporates, as well as the calling member name, the source line number and, where applicable, apparently, the expression number on the line of the call invocation. I simply use the ToString() method to subsequently record this in a Write event.

The field output of the methods is generally otherwise structured to accept a string message and a string of additional data. A duration spanning event also records the duration, in milliseconds, of the "span" and a more general "task-oriented" event can also record the name of a task and also what function the task is undertaking via an enumeration.

All of the EventSource methods as well as two referenced task-oriented enumerations are localised via the recommended ETW RESX strategy as specified by the Microsoft.Diagnostics.Tracing package.

The solution has no other dependencies in terms of using the ETW EventSource features. However, the generation of ETW messages requires some method to "view" these messages. Hence, as well as the "ordinary" usage of a Unit Test class I have also incorporated a Console Test application so that event monitoring can be undertaken by either PerfView or the Semantic Logging Application Block (SLAB) Event Listener in console mode.

I have also referenced (but there is no dependency upon), in this solution, the FsEye (Version 2.1.0) package of Stephen Swenson since, in general, I find its usage extremely helpful and, in terms of learning F#, its continual presence sets a high standard for us "learners" - especially with regard to reflection.

As this is my "first" F# application I expect errors and questionable performance as well as perhaps incorrect or inappropriate use of language features and omission of language features that might better perform the task at hand. In any event I would be much obliged for any constructive criticism.

Assertion Tracing

Note that the Swenson Unquote.test function which is used in saTrilogy.Etw for assertion testing emits output specific to the runtime environment. That is, to quote Stephen Swenson...

Unquote chooses its output source as follows

  • if loaded in FSI then print to the console
  • else if xUnit or NUnit loaded in currently executing assembly, then use appropriate test failed methods
  • else throw a Swensen.Unquote.Assertions.AssertionFailureException with a message

I'm not quite so particular; I presume that if you're wishing to undertake ETW tracing then you're doing it in "Release Mode" so assertion failures will raise an exception otherwise the result is unit. The Logging code presumes that an exception is an assertion failure and that if "nothing happens" the assertion is true. This means that when you "test" saTrilogy.Etw you may not get whay you "expect" when invoking Logging.Emit.Test. That is, in the given tutorial although the assertion <@ 2. ** 3. - 1. = 6. @> is false since you are executing it from F# Interactive no exception will be raised - so the saTrilogy.Etw. EventSource assumes that the assertion is successful and records it in the log as such - as is shown in the log output underneath the tutorial code.

However, if you run such an assertion in a Unit Test or via our Console Test project you will get a "different" result - such as (from PerfView)...

ThreadID=8,344 FormattedMessage="Assertion Failure" Invoker="saTrilogy.Etw.Console.Tests+main@25-5"
  Message="Swensen.Unquote.AssertionFailedException: 
           Test failed: -> 2.0 ** 3.0 - 1.0 = 6.0 -> 8.0 - 1.0 = 6.0 -> 7.0 = 6.0 -> false
             at saTrilogy.Etw.Logging.Test(String invoker, FSharpExpr`1 expr, Boolean abend)
               in U:\Publish\saTrilogy.Etw\src\saTrilogy.Etw\Logging.fs:line 369"