- Start Date: (fill me in with today's date, 2019-02-01)
- RFC PR: (leave this empty)
- ReactiveUI Issue: (leave this empty)
Application Performance Monitoring Integration
Summary
To offer Application Performance Monitoring integration similar to how the Logging integration works.
Motivation
Scenarios
As a developer I want to know how often a command\event subscription is used. The duration and success rate
As a developer I want to know of failures
As a developer I want to be able to group events by feature/subfeature (with subfeature recursion)
I appreciate the examples are focused at ReactiveCommand. But you could define a feature as being a view\viewmodel.
Part of this belongs at the splat level as the APM toolset could be a direct target of the ILogger, depending on the features offered by the APM library.
Detailed design
When I played with the concept I used a disposable class so start event happened at construction. End event happened as dispose. I could call the error method as required (Ie exception). Alternatively I could just use generic helper methods and never touch the IDisposable wrapper.
The idea would be either to have a feature usage tracking aware subclass to reactive object or allow an IEnableFeatureUsageTracking extension interface. You could then hook up a reactive command that is aware of the parent feature and allows specifying the subfeature details.
Possible consumers
Visual Studio App Center (with appreciation wpf\winforms etc still trailing on support)
New relic
Application insights
Exceptionless
There was an interface for the target framework to have flexibility on how it works
public interface IFeatureUsageTrackingSession<out TReferenceType> : IFeatureUsageTrackingSession
{
TReferenceType FeatureReference { get; }
TReferenceType ParentReference { get; }
string FeatureName { get; }
}
There were interfaces so ReactiveUI and other consumers wouldn't get bogged down in the design details of the target framework
public interface IFeatureUsageTrackingSession : IDisposable
{
IFeatureUsageTrackingSession SubFeature(string description);
void OnException(Exception exception);
}
public interface IEnableFeatureUsageTracking
{
}
A sample implementation for App Insights
namespace Splat.ApplicationInsights
{
using System;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
public class ApplicationInsightsFeatureUsageTracking : IFeatureUsageTrackingSession<Guid>
{
private readonly TelemetryClient _telemetry;
public ApplicationInsightsFeatureUsageTracking(string featureName) : this(featureName, Guid.Empty)
{
}
internal ApplicationInsightsFeatureUsageTracking(string featureName, Guid parentReference)
{
this.FeatureName = featureName;
this.FeatureReference = Guid.NewGuid();
this.ParentReference = parentReference;
this._telemetry = Locator.Current.GetService<TelemetryClient>();
TrackEvent("Feature Usage Start");
}
public Guid FeatureReference { get; }
public Guid ParentReference { get; }
public string FeatureName { get; }
public void Dispose()
{
TrackEvent("Feature Usage End");
}
public IFeatureUsageTrackingSession SubFeature(string description)
{
return new ApplicationInsightsFeatureUsageTracking(description, this.ParentReference);
}
public void OnException(Exception exception)
{
var telemetry = new ExceptionTelemetry(exception);
PrepareEventData(telemetry);
this._telemetry.TrackException(telemetry);
}
private void TrackEvent(string eventName)
{
var eventTelemetry = new EventTelemetry(eventName);
PrepareEventData(eventTelemetry);
this._telemetry.TrackEvent(eventTelemetry);
}
private void PrepareEventData<TTelemetry>(TTelemetry eventTelemetry) where TTelemetry : ISupportProperties
{
eventTelemetry.Properties.Add("Name", FeatureName);
eventTelemetry.Properties.Add("Reference", FeatureReference.ToString());
if (ParentReference != Guid.Empty)
{
eventTelemetry.Properties.Add("ParentReference", ParentReference.ToString());
}
}
}
}
How we teach this
In terms of Splat have some wrappers that show simple usage. Doesn't necessarily need the IDisposable pattern.
public static async Task SubFeatureAsync(
this IFeatureUsageTrackingSession featureUsageTracking,
string featureName,
Task action)
{
using (var subFeature = featureUsageTracking.SubFeature(featureName))
{
try
{
await action;
}
catch (Exception ex)
{
subFeature.OnException(ex);
//re-throw so parent logic can deal with
throw;
}
}
}
ReactiveUI integration into the ReactiveCommand itself. Or show how to use the Splat helpers inside the executing subscription. Draw back to this is multiple try\catch.
Aside from Feature Usage Tracking. There is also the error\crash reporting piece, we could report UnhandledExceptions at the RxApp level. You then have a training piece available that as part of testing and development people can use an APM tool to see the list of Exceptions getting down to the core.
Feature: The top level ViewModel.
SubFeature: ReactiveCommand, Event, Possibly even the IViewFor<>
It can be sold as an opt-in feature to new and existing users. Same way the logging works.
In terms of ReactiveCommands. do you want an optional string argument for the feature name that dictates if a command even uses this?
Drawbacks
- Adding an extra layer of integration to support.
- Users still need knowledge of the feature\subfeature structure and how to utilise the APM tool.
- Visual Studio App Center limits to 200 distinct named events.
source: https://docs.microsoft.com/en-us/appcenter/analytics/event-metrics
source: https://docs.microsoft.com/en-us/appcenter/sdk/analytics/uwp
Might need something like the code below. But dictating to users how to Feature Usage Tracking in a pre-defined format?
Analytics.TrackEvent("FeatureUsage", new Dictionary<string, string> {
{ "Name", featureName },
{ Reference, FeatureReference},
{ ParentReference, ParentReference},
});
Alternatives
Offer interfaces but not the end integrations and patterns of implementations.
Or have ways to overload.
Unresolved questions
Is it actually useful \ desirable?
What level of integration for Splat\ReactiveUI?
How to avoid overcomplicating ReactiveObject and making this opt in? or just treat the inheriting classname as the default featurename? if so, use weaving etc rather than reflection?
People need to be aware of the costings of the APM tool they choose. This is around giving the facilities to make decisions based on what users are experiencing.
Application Performance Monitoring Integration
Summary
To offer Application Performance Monitoring integration similar to how the Logging integration works.
Motivation
Scenarios
As a developer I want to know how often a command\event subscription is used. The duration and success rate
As a developer I want to know of failures
As a developer I want to be able to group events by feature/subfeature (with subfeature recursion)
I appreciate the examples are focused at ReactiveCommand. But you could define a feature as being a view\viewmodel.
Part of this belongs at the splat level as the APM toolset could be a direct target of the ILogger, depending on the features offered by the APM library.
Detailed design
When I played with the concept I used a disposable class so start event happened at construction. End event happened as dispose. I could call the error method as required (Ie exception). Alternatively I could just use generic helper methods and never touch the IDisposable wrapper.
The idea would be either to have a feature usage tracking aware subclass to reactive object or allow an IEnableFeatureUsageTracking extension interface. You could then hook up a reactive command that is aware of the parent feature and allows specifying the subfeature details.
Possible consumers
Visual Studio App Center (with appreciation wpf\winforms etc still trailing on support)
New relic
Application insights
Exceptionless
There was an interface for the target framework to have flexibility on how it works
There were interfaces so ReactiveUI and other consumers wouldn't get bogged down in the design details of the target framework
A sample implementation for App Insights
How we teach this
In terms of Splat have some wrappers that show simple usage. Doesn't necessarily need the IDisposable pattern.
ReactiveUI integration into the ReactiveCommand itself. Or show how to use the Splat helpers inside the executing subscription. Draw back to this is multiple try\catch.
Aside from Feature Usage Tracking. There is also the error\crash reporting piece, we could report UnhandledExceptions at the RxApp level. You then have a training piece available that as part of testing and development people can use an APM tool to see the list of Exceptions getting down to the core.
Feature: The top level ViewModel.
SubFeature: ReactiveCommand, Event, Possibly even the IViewFor<>
It can be sold as an opt-in feature to new and existing users. Same way the logging works.
In terms of ReactiveCommands. do you want an optional string argument for the feature name that dictates if a command even uses this?
Drawbacks
source: https://docs.microsoft.com/en-us/appcenter/analytics/event-metrics
source: https://docs.microsoft.com/en-us/appcenter/sdk/analytics/uwp
Might need something like the code below. But dictating to users how to Feature Usage Tracking in a pre-defined format?
Alternatives
Offer interfaces but not the end integrations and patterns of implementations.
Or have ways to overload.
Unresolved questions
Is it actually useful \ desirable?
What level of integration for Splat\ReactiveUI?
How to avoid overcomplicating ReactiveObject and making this opt in? or just treat the inheriting classname as the default featurename? if so, use weaving etc rather than reflection?
People need to be aware of the costings of the APM tool they choose. This is around giving the facilities to make decisions based on what users are experiencing.