Feature name:
- High Performance Logging
Feature Description
Microsoft recommends using LoggerMessage
to define delegates that are cacheable and reduce the amount of allocations that are created when compared to the normal extension methods. But don’t just believe me here is their write-up.
There are two general ways I have seen this implemented:
- An encomposing
LoggerExtensions
class- This class would hold all the logging events for that project/namespace (design decision)
- Depending on how many events there are in the chosen scope it could get large and hard to navigate/organize.
- Invocation Example:
_logger.UserCreated();
- Example
- Inner static
Log
class- This would be a inner static class that would hold all the logging events for the class it is in.
- This would be much more targeted so you would know where the events are but it would also create more code smell at the bottom of a lot of files.
- Invocation Example:
Log.UserCreated(_logger);
- Example
An example of just one place this could be implemented in the server repo is here.
Example 1.
public static class LoggerExtensions
{
private static Action<ILogger, string, Exception?> _sendEmailFailed;
// More delegates
static LoggerExtensions()
{
_sendEmailFailed = LoggerMessage.Define(LogLevel.Warning,
new EventId(1, nameof(SendEmailFailed),
"Failed to send email. Re-retying...");
}
public static void SendEmailFailed(this ILogger logger, Exception ex)
{
_sendEmailFailed(logger, ex);
}
// More event methods
}
// Usage:
// *Removed for brevity*
catch (Exception e)
{
_logger.SendEmailFailed(e);
}
Example 2.
public class AmazonSesMailDeliveryService : IMailDeliveryService, IDisposable
{
// Removed for brevity
public async Task SendEmailAsync(MailMessage message)
{
// Removed for brevity
catch (Exception e)
{
Log.SendEmailFailed(_logger, e);
}
}
private static class Log
{
private static Action<ILogger, string, Exception?> _sendEmailFailed;
static LoggerExtensions()
{
_sendEmailFailed = LoggerMessage.Define(LogLevel.Warning,
new EventId(1, nameof(SendEmailFailed),
"Failed to send email. Re-retying...");
}
public static void SendEmailFailed(ILogger logger, Exception ex)
{
_sendEmailFailed(logger, ex);
}
}
}
Some of the conventions I have used and described can be changed but those are what I have seen used. I am willing to work on this I would just want to settle on the conventions you would want used and some promise that it is something Bitwarden is interested in.
Clients / Repos Affected:
- Server
Timeline to completion (estimate):
ETA: Q2/2021