liveBook · Manning

Monitoring

As explained in Unit Testing Principles, Practices, and Patterns

Logging is the recording of application events, state, or diagnostic information for later observation or analysis.

Logging records application events or diagnostic information, but its testing value depends on whether those records are observable behavior or merely an implementation detail. section 8.6

Apply these distinctions when designing and testing logging:

  • Test logs when customers, clients, business stakeholders, or logging-library users depend on them; avoid testing developer-only messages that can change freely. section 8.6
  • Separate domain-significant logging behind a DomainLogger, or represent significant changes as domain events instead of coupling domain logic directly to log formatting. section 8.6
  • Prefer structured logging when data should support multiple renderings, such as flat files, JSON, or CSV. section 8.6
  • Choose logger ownership deliberately: static fields reduce parameter passing, while explicit injection makes the dependency visible. section 8.6

Observable logging in a user workflow

A User.ChangeEmail operation logs its beginning, completion, and user-type changes. If those messages satisfy a business requirement, test them; if developers alone consume them, treat them as implementation detail. section 8.6

Listing 8.3. An example of logging in User
public class User
{
    public void ChangeEmail(string newEmail, Company company)
    {
        _logger.Info(                                            #1
            $"Changing email for user {UserId} to {newEmail}");

        Precondition.Requires(CanChangeEmail() == null);

        if (Email == newEmail)
            return;

        UserType newType = company.IsEmailCorporate(newEmail)
            ? UserType.Employee
            : UserType.Customer;

        if (Type != newType)
        {
            int delta = newType == UserType.Employee ? 1 : -1;
            company.ChangeNumberOfEmployees(delta);
            _logger.Info(                                        #2
                $"User {UserId} changed type " +                 #2
                $"from {Type} to {newType}");                    #2
        }

        Email = newEmail;
        Type = newType;
        EmailChangedEvents.Add(new EmailChangedEvent(UserId, newEmail));

        _logger.Info(                                            #3
            $"Email is changed for user {UserId}");
    }
}

Inspect the concrete ChangeEmail logging example before comparing DomainLogger, structured logging, domain events, and logger-injection alternatives. section 8.6

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Works through concrete logging code, refactorings, structured data, domain events, and dependency choices rather than offering only a definition.
Examples
Uses User.ChangeEmail, DomainLogger, structured log renderings, domain events, static logger storage, and explicit logger injection.
What it assumes
Assumes distinguishing observable behavior from implementation detail and recognizing side effects in out-of-process dependencies.
What you can do after
Evaluate/understand which logging behavior warrants tests and choose an appropriate coupling and representation strategy.
How it connects
Connects logging with observable behavior, implementation details, structured logging, domain events, and dependency injection.

Also explained in

Compare how 40 books explain monitoring →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.