SharpSenz 0.1.0
See the version list below for details.
dotnet add package SharpSenz --version 0.1.0
NuGet\Install-Package SharpSenz -Version 0.1.0
<PackageReference Include="SharpSenz" Version="0.1.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add SharpSenz --version 0.1.0
#r "nuget: SharpSenz, 0.1.0"
// Install SharpSenz as a Cake Addin #addin nuget:?package=SharpSenz&version=0.1.0 // Install SharpSenz as a Cake Tool #tool nuget:?package=SharpSenz&version=0.1.0
SharpSenz
SharpSenz is a C# intsrumentation library for decoupling reactive code from the main application code.
SharpSenz enables:
- Abstracting logging / traces / monitoring away
- Unit tests simplification
- Being able to decide on a specific logging frameworks later
- Completely replace logging framework or have many of them at any stage of the project
- Implement additional reactive logic like performance counters collection or message bus communication without touching the main application code
Overview
SharpSenz utilizes Roslyn compiler capabilities to generate abstract interface calls as you type your main application code in.
The implementations of the generated interface may do whatever is practical: logging / updating performance counters / cross-services communication / anything that comes to your mind later.
It allows the developer not to take dependencies on any monitoring library during the early stages of the project and keep the architecture clean.
It allows to delay the decision about monitoring framework to the latest responsible moment as well as have multiple monitoring implementations at the same time without changing the original code.
It also makes the unit / component testing easier by making all the reactive code optional.
Walkthrough
The below explanation looks long, but the actual work is really fast as all you need to do is to press "Alt + Enter" few times.
1. Example class without logging
Take a look at this siimple project. Hyperspace is the component we will apply an instrumentation to. We can think about it as one of the components of the Spaceship. Spaceship is the main program which calls to the Hyperdrive class of the Hyperspace project. Next we will apply instrumentation to the JumpThroughHyperspace method of the Hyperdrive class.
2. Installing the SharpSenz NuGet package
(This step is a temporary workaround for the promlem we don't know how to solve) After installing the SharpSenz NuGet Package you need to comment out two XML lines as specified in the image below.
Now we can begin instrumenting our code
3. Adding the [SignalsSource] attribute
In our hyperspace example we want the Hyperdrive class to publish few signals. Later we could implement this signals as log messages, performance counters or anything else.
First thing we need to do is to mark Hyperdrive class with the [SignalSource] attribute.
After adding the appropriate "using" statement, the entire Hyperdrive class got few compilation errors from SharpSenz Roslyn analyzers. Please don't be afraid, we will immediatelly fix them with the SharpSenz Roslyn Code Fixes.
4. Making class Partial
The first fix is to make Hyperdrive class partial since the generated code resides in a separate file.
5. Adding the SignalsMultiplex class and member
Next we will add an inner class for spreading the signals to all registered signals receptors. We call this class "Multiplex".
And we will add a new instance of our Multiplex class.
With both class and its instance defined the code looks like in the image below.
6. Adding the signal to the existing method
It's time to add the actual signals to our code. We recommend to add the signal staring with its message string.
Just add the comment starting with the "SIG:" prefix and put your message afterwards.
Each signal comment needs a corresponding multiplex method call.
Apply the appropriate code fix to automatically get the multiplex method name containing both calling method name and the message.
After all the multiplex method calls were added the code looks like in the image below.
Wait, but it compiles!?!
If you compile this code right now, it will surprisingly be compiled successfully. This happens thanks to the automatic roslyn code genegation of the Multiplex class. We will observe the automatically generated code in a moment.
This automatic code generation is the main purpose of the SharpSenz project
You can add parameters to the multiplex method calls. Code generation will take these parameters into consideration automatically.
Just type the parameters into the method call itself!
After adding parameters to the multiplex method calls the code looks like in the image below.
Now let's take a look at the generated code.
7. Observing the generated SignalsMultiplex and ISignalsReceptor classes
As you can see in the image below each signal gets its own method with the correspondings parameters.
Signal context contains all the information about where the signal comes from. All this information is constant value, so no perfromance penalties here.
Multiplex responsibility is to catch the correct signal context and call all the ISignalsReceptor implementations.
ISignalsReceptor definition is pretty straightforward.
8. Observing main
Now let's take a look at the main module of the system.
Main remains unchanged. And there is some power in this statement, since there is no dependency on any specific logging framework. The code still compiles and run successfully without dependencies.
This makes Unit Testing much easier.
9. Unit Testing the component without any dependency
As you can see in the image below Unit Testing is possible without any dependency.
10. Developing the console logging
Let's develop some implementations of ISignalsReceptors. We can start with the simplest logging to the Console.
We recommend to implement ISignalsReceptor interface explicitly. This way everytime the interface changes, you will not miss the methods that are not needed anymore.
You can also find examples of signal context usage in the implementation below.
The usage is straightforward.
11. Adding NLog logging instance
The beauty of the decoupling is that we can have multiple implementations of the logging mechanism. This implementations can live in our code base at the same time and could be changed even at runtime. This is not the case with the traditional approach to logging.
Let's add an implementation that calls to NLog.
And the fact the Hyperspace project itself remains untouched is especially satisfying.
Let's have both loggers to work in parallel just make a point they can.
12. Adding Performance Counters and MessageBus instances
Later we can decide to add Performance Counters implementation or some message bus logic.
Again the Hyperspace project remains untouched.
Hope you've enjoyed this walkthrough.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Pre-alpha release