Another type of information we may collect in the Logging Layer is performance metrics: namespace Logging.Services { public class ServiceOne : FunctionalLayer.Services.ServiceOne { private ILogger _logger; // writes to a file, or a service private Metrics _metrics; // service that records metrics private StopWatch _timeCallA; ... public override Response CallA(Request request) { _logger.WriteLine(LogLevel.Info, "CallA Started"); _metrics.Increment("ServiceOne.CallA Called") _timerCallA.Restart() var results = base.CallA(request); _timerCallA.Stop(); _logger.WriteLine(LogLevel.Info, "CallA Completed"); _metrics.InsertCallLength("ServiceOne.CallA", _timerCallA.ElapsedMilliseconds); if (results.Success) { _metrics.Increment("ServiceOne.CallA Success") } return results; } } }

The information we are getting here is:

  1. That the service call was started.
  2. How many times the service call was actually called.
  3. That the service call completed.
  4. How long it took the service call to complete.
  5. How many times the service call was executed with no errors.

The above example appears to have business logic in it due to the fact we are looking at results.Success. However, this is not business logic for one simple reason, adding or removing the above code would have no impact on the core functionality. Simply put, you can read values from the Functional Layer, as long as you don't change them in anyway.

As mentioned in Start / Stop Logging, it is very important to prevent exceptions from escaping the Functional code that is being called. If the exception does escape, then we will lose all information from points 3, and 4. We technically would not be losing information from point 5, since it counts successful completions of the code, and having an exception escape is a very good indicator that the code did not complete successfully.

Note: any metrics that involves error tracking may still need to be the in the Functional Layer. For example, we may have a setting that causes any external call that exceeds a certain amount of time (i.e. timeout) to be be considered an error state. This measurement needs to be done inside of the Functional Layer since the time is being used to determine if an error should be created.

You may still want to expose the timer used to determine if a timeout did or did not occur to the Logging Layer. This way, the Logging Layer does not have to create an additional timer to measure and record the elapsed time. One possible way to expose the information to the Logging Layer is to put the timer value in response that is returned by the Functional Layer; at which point, the Logging Layer may simply read the appropriate value it needs from the response.

Next: Other Logging Considerations