Goals - GibraltarSoftware/Loupe.Agent.Core GitHub Wiki

First Do No Harm

The guiding principal for each step of the Loupe agent implementation is to ensure to the maximum degree possible that adding the Loupe Agent to an application will not harm an application. Harm can come in many forms - it could be making the application slower, serializing requests so they no longer run as parallel as they did previously, tying up the thread pool so application threads don't have the same parallelism as they would, or throwing back errors that alter code flow.

This philosophy shows up in several design decisions that are atypical for .NET applications:

  1. Don't Throw Exceptions through the Client API - Client methods of logging, metrics, and in general anything that a typical client would do can not throw exceptions as those would alter the flow of the application at inopportune moments.
  2. Avoid Shared Thread Pools - Any pool of threads that may be shared with the client should be avoided to prevent starvation of the client. Instead, Loupe prefers dedicated threads for itself that can have clear lifecycle and exception management.
  3. Custom String.Format - To capture the maximum data possible a customized string.format is used that will return a string even if there are problems with one or more insertion value or a miss-match between the insertion values and the insertion string. This is part of avoiding throwing exceptions to the caller and maximizes the diagnostic information available even if the client application has a coding error.

Provide an Outstanding Experience for Beginners

The overwhelming number of developers do little or no logging and have little time or inclination to learn the intricacies of a telemetry API. The Loupe client API is designed with this in mind on several fronts:

  1. Safe Defaults for Configuration - The goal is the overwhelming balance of users can have a trivial Loupe configuration, never adjusting 90% of the available configuration options. This includes automatically binding to Console and Trace and other steps designed to maximize the data gathered by default with little or no action on the part of the developer.
  2. Completely Thread Safe - The entire Loupe.Agent API is designed so the caller never has to consider multithreaded issues like re-entrancy, race conditions, or locking. The API shall be designed so they get correct behavior without having to consider multithreading. Parts of Loupe.Agent.Core do not follow this philosophy as they are not for beginners.
  3. Global Logger and Trace Support - With a single Log object to invoke methods on beginners can record information to Loupe without having to worry about Dependency Injection, performance issues by excessive object creation, or other code ceremony aspects of having instance loggers. This matches the basic built-in .NET Trace logging for easy conversion.

Support Third Party Logging API

Many potential Loupe users will already be using another logging system. While our experience is that over time most shops that adopt Loupe turn to it as their primary or even only API the ability to ingest data from their existing code is essential. It allows users to quickly get up and running with Loupe seeing useful data from work they've already done, avoids intra-organizational conflict where a standard logging system has already been chosen, and provides an escape hatch for organizations.

Frequently organizations that are looking at Loupe have initial concerns about what they would do if they need a feature we don't have (answer: if you like your current logging API experience you can keep using it) or if they want to migrate away to another system having to rewrite their code. Making sure we have excellent support for clients using common logging API's eases these concerns. Since our main gaols are to make sure developers gather information and are able to dramatically improve the quality and supportability of their applications it doesn't really matter if they use our API directly or via a third party.