How to Extend Sitecore Contextual Logging with New Relic One
Over the last decade, the Sitecore Experience Platform (XP) has evolved from a monolith into a complex set of distributed microservices. This increased complexity has required our Managed Services team to evolve its approach to troubleshooting Sitecore application and infrastructure failures. It led us to adopt observability practices with full-stack observability tools.
In this post we’ll illustrate how we bolstered our observability practices by extending native Sitecore logging capabilities using structured and contextual logging with New Relic One.
Observability and Contextual Logging
Observability has three key pillars: metrics, distributed traces, and logs. Metrics are system-centric data, like counters and gauges, that help you monitor the state of your system. Distributed traces are request-centric data that help you understand flows, timing, and the dependency details of web requests. Logs are timestamped records that provide you with information about system and application events.
Most observability tools can easily collect metrics and distributed traces of a Sitecore application using their native agents. The API of these agents allows you to extend the information you can collect with custom properties, like Sitecore context data or identity user data. However, the methodology to collect logs is different among observability tools. A big differentiator among tools is the ability to correlate application logs with web request traces. This is also known as contextual logging. It requires enriching log records with additional properties about their correlated traces, by leveraging the API of the .NET agents.
Contextual logging lets you identify the web request trace associated with a log event and reduces the time needed to troubleshoot a failure. Without contextual logging, this association is performed manually, by a human person, which creates an opportunity for inaccuracy and an incorrect analysis.
The Limitations of Sitecore Logging
Sitecore logging functionality is based on a custom implementation that resembles the Apache Log4Net for .NET library project, without directly referencing it in its solution. The default log appender used by the Sitecore application writes plaintext log records in the file system. These records are easy to read by a person, but not so easy to parse by a log collection tool, particularly multiline records with nested stack information. These tools prefer the collection of structured logs, where the log record has a defined message format, usually in a key-value structure, that treats the logs as data sets instead of free text messages.
Sitecore Host applications, like Identity Server, Horizon applications or Commerce engines, already support structured logging with Serilog. Hopefully the rest of the Sitecore platform will evolve and introduce structured logging in the future.
In the meantime, we have extended the Sitecore logging functionality to implement structured logging and contextual logging for New Relic. This uses the New Relic .NET Logging Extension for log4net project as starting point and modifies it to work with the Sitecore.Logging library.
Creating Sitecore Structured Logging in Context for New Relic
A custom implementation is needed because the Sitecore.Logging library uses the same names for namespaces for implemented objects as the Apache Log4Net library. This introduces conflicts when using other libraries that have dependencies with the Log4Net library. Two main objects have been implemented:
- A custom appender type, to enrich the logs metadata with correlation data with telemetry New Relic traces, using the New Relic .NET agent
- A custom layout, to produce structured logs in JSON format, enriched based on the log event type
Implementing Custom Appender Type
The custom NewRelicAppender type object is implemented by inheriting the ForwardingAppender class of the Sitecore.Logging library and adapting the original New Relic developers’ implementation, as follows:
Creating a Custom Layout
The custom NewRelicLayout object is implemented by inheriting the LayoutSkeleton class from the Sitecore.Logging library and adapting the original New Relic developers’ implementation, as follows:
The Format method in the NewRelicLayout class is responsible for enriching the log data with trace correlation properties and for formatting the log message in a structured JSON object.
Sitecore Configuration Patching
The default Sitecore log appenders configuration can be modified to use the custom implemented type and layout with a Sitecore configuration patch. The following example shows only the patching of the LogFileAppender appender and, of course, this implementation can be applied to other Sitecore log appenders as well.
A Structured Log Example in Context
Once this custom implementation is in use, the Sitecore logs are enriched and rendered in a JSON structured format. This is an example of a Sitecore error log message with enriched correlation data, expanded in multiline format for readability:
The trace.id and span.id properties are correlation data used by New Relic to associate the log event with a particular trace (a distributed web request) and span (portion of a distributed web request in a single sub-application).
Easier Sitecore Logging and Troubleshooting
Structured logs data allow you to manage log record properties separately in your observability tool. This simplifies common analysis activities like querying the data or aggregating the data by a specific property. The correlation of the log events with web request traces helps you discover the root cause for transaction failures faster. An easier and more powerful analysis lets you significantly reduce the time to investigate and resolve failures. This makes everybody happier: the users and the stakeholders of your web application, and the support team managing it.
Need help troubleshooting your Sitecore applications or infrastructure? Learn more about our Maintenance and Application Support services or contact us to learn how we can keep your website running smoothly.