Assembly Roles - GibraltarSoftware/Loupe.Agent.Core GitHub Wiki

The assemblies at the heart of the Loupe Agent are:

  • Loupe.Serialization: The proprietary Loupe binary serializer. It shouldn't require extension directly although may be enhanced for performance updates.
  • Loupe.Agent.Core: The heart of the Loupe Agent and includes the conversion from memory to serialized types, the threading infrastructure for asynchronously taking actions, and the central logic around sessions.
  • Loupe.Agent: The primary public API. Consumers of Loupe will use this as their entry point to Loupe features.
  • Loupe.Agent.Common: Types and implementations that need to be shared by Loupe.Agent and Loupe.Agent.Core so that an application can reference this assembly and either of those. For example, the shared enumeration types and the primray logging extension methods live here.

What About Platform Specific Code?

Previously, the Gibraltar.Agent included as much platform-specific functionality as was available referencing only the .NET Framework. This meant it was deeply aware of Windows-specific features like performance counters and WinForms capabilities since they were available on every version of the .NET Framework.

The primary goal of Gibraltar.Agent was to have as much functionality available in a single assembly to minimize the complexity of reference management and unexpected missing capabilities.

For Loupe Agent a somewhat opposite strategy is being pursued with the main assemblies covered here representing the shared functionality used by all versions of .NET Framework and .NET Core on all platforms - Windows, mobile, and Linux. Features useful only for WinForms, ASP.NET (*), Entity Framework, etc. should all be placed in their own separate assemblies so developers can incorporate them when they use those technologies.

Loupe.Agent

This assembly is the primary reference for any Loupe client that wants to record telemetry with Loupe. Between this assembly and Loupe.Agent.Common clients should find every type they need for typical Loupe usage. The goal of this API is to provide an accessible, easy experience without overwhelming developers with excessive numbers of types or method choices to pick through to satisfy all but the esoteric telemetry use cases.

The Loupe.Agent itself will depend on Loupe.Agent.Core for performing all Loupe actions, it just provides a more convenient, curated API to those actions. Maintainers should endeavor to avoid duplication of logic between Agent and Agent.Common even if that incurs minor performance penalties. Shared code implementation should be factored into Loupe.Agent.Common where feasible or avoided by having Loupe.Agent form a thin veneer over Loupe.Agent.Core.

Every effort should be made to avoid breaking changes in Loupe.Agent. End users can expect to upgrade to any minor version within a major version of Loupe and simply recompile. Applications should be able to employ assembly redirects to use later versions of Loupe.Agent without breaking applications compiled against older versions.

Backwards Compatibility with Gibraltar.Agent

It isn't clear at this point whether backwards compatibility should be done within Loupe.Agent or using a separate assembly dedicated to backwards compatibility. The goal is that any application using Gibraltar.Agent can be upgraded to this line of Agents and recompiled without any code changes, however assembly redirects will not necessarily work.

Loupe.Agent.Common

Types or other implementation that needs to be shared by Loupe.Agent and Loupe.Agent.Core should be placed in this assembly. Since client applications are allowed to reference Loupe.Agent or Loupe.Agent.Core, some functionality (such as the primary logging API) is abstracted into this assembly so that the same implementation can be shared by clients referencing either route to Loupe.

Loupe.Agent.Common is at the lowest part of the Loupe assembly reference chain; it can't reference any other Loupe assembly however it may reference third-party assemblies provided that it is acceptable to take a dependency on these assemblies for all Loupe applications.

Loupe.Agent.Core

Core is the primary assembly of Loupe with the central logic for what data can be managed, how it is recorded, how it is sent to other systems, configuration of Loupe and the lifecycle of the Agent. To enable extensibility, Core exposes types for each stage of the Loupe pipeline. This means the overall API surface area may be daunting for new users. This is accepted because it's not expected that developers will directly reference this assembly unless they are tryin to extend Loupe itself.

While it isn't expected that most Loupe clients wll reference Core, an effort should be made to break out the assembly namespaces so that the various extension pointS are reasonably grouped together. For example, if working with Loupe to provide a more customized telemetry capture capability it shouldn't require wading through all of the serialization types or interfaces and types used for the underlying data storage system.

Change to Loupe.Agent.Core are not required to meet the same backwards compatibility rules as Loupe.Agent, however a reasonable effort should be made to not break older clients. When making a breaking change it's preferable to do so in a manner that prevents them from compiling until corrected instead of allowing errant behavior.

Loupe.Serialization

Serialization handles the generic serialization and deserialization of Loupe data to a compact, typed binary format. It isn't expected that significant functional changes will be necessary in this library however it may be modified to improve performance where possible. Backwards compatibility is essential with the serialization library to ensure that any file ever written with the Loupe Agent (or Gibraltar.Agent) can be reads back. Change requests to this assembly will be scrutinized heavily and should be accompanied with unit tests.