Monitoring vs Observability

What is the difference between monitoring and observability?

Monitoring is process of collecting live events from your application, traces, debug messages, warnings and exceptions. The same process may involve sending those events to some storage or application that analyze or visualize those messages. I.e. in asp.net core applications monitoring of application involves calling a ILogger and sending those logs or critical exceptions to AppInsights. Monitoring may also involve activity of development team members to active watch those logged messages for any potential errors or problems that may impact availability of production environment.

Observability is on the other hand is analyzing messages produced by monitoring process to understand behavior of application and reason about it internal state, if this state is expected (correct behavior, ‘application works ok’) or may be unexpected (erroneous state, database is down, endpoints returns 500 etc). Typically involves dashboard with several metrics from monitoring, exceptions, response times, number of not OK responses in time, long database queries, number of active users etc (i.e. App Insights dashboard in asp.net core). Monitoring process of an application (as human activity) is typically using such observability dashboard.

So what is the difference between Observability and Monitoring? Observability is possible because Monitorin of an application was implemented. If metrics and logs would not be collected and stored system is not observable.

Basically Monitoring is collecting logs and metrics, while Observability is feature of the system enabled by such process.

Covariance and Contravariance

  • enables implicit reference conversions for
    • arrays
    • delegates
    • generic type arguments
  • Covariance preserves assignment compatibility
  • Contravariance reverses assignment compatibility
  • allows for matching signatures of delegates and method groups
    • to assign to delegates from method that returns more derived types – covariance
    • to assign to delegates from method that returns less derived types – contravariance
  • Covariance and Contravariance are supported in Generics for implicit conversions for type parameters
    • allows method to have more derived return type than defined by generic type parameter of the interface
    • this allows implicit conversions from one generic interface to another (from IEnumerable<string> to IEnumerable<object> even if first does not inherits from second)
    • allows generic types to have less derived argument types than specified by the generic parameter of the interface (implementation of IEqualityComparer<BaseClass> can be implicitly converted to IEqualityComparer<DerivedClass> because IEqualityComparer.Equals is contravariant)
    • implicit conversions works for interfaces but not classes that implement from those interfaces (i.e. this won’t work List<Object> list = new List<String>())

Assignment compatibility is when object of a more derived type is assigned to an object of a less derived type.

object obj = str;

String can be represented as an object because it is reference type and inherits from System.Object.

Covariance is when object that is instantiated with a more derived type argument is assigned to an object instantiated with a less derived type argument.

IEnumerable<string> strings = new List<string>();

List<> inherits from IEnumerable<string> so can be represented as such.

Covariance in generic interface:

interface IEnumerable<out T>

Contravariance is when object that is instantiated with a less derived type argument is assigned to an object instantiated with a more derived type argument.

static void SetObject(object o) { }
Action<object> actObject = SetObject;  
Action<string> actString = actObject;

Contravariance in generic interface:

interface IEqualityComparer<in T>

SupressFinalize in IDisposable interface

  • informs GC that object does not need to be added to finalizer queue
  • finalizer execution is not deterministic and objects can live for long time in queue – this is optimization technique
  • to make sure that object disposes of any unamanaged resources even if Dispose will be not called we need to implement finalizer

Basically finalizer execution time is not deterministic. We cannot predict when this will be called and till that time – object is existing and still taking memory space. Since we are controlling creation and disposal of those resources we can say to GC: ‘Do not worry about that! It already had been taken care of!’. So this way object will be destroyed sooner, leaving this space to be used by something else possibly.

The Dispose() method must call Dispose(true) and should suppress finalization for performance.

MSDN


Further read:

https://learn.microsoft.com/en-us/dotnet/api/system.idisposable?view=net-6.0