Logging with H.Necessaire
Logging mechanism of H.Necessaire; logging is basic building block in any app, and therefore H.Necessaire tries to make it as painless and simple as possible.
Logging is a basic building block in any app, and therefore H.Necessaire tries to make it as painless and simple as possible.
Usage
dotnet add package H.Necessaire
Behind the scenes
Though the usage is simple, under the hood, there's quite a path to be walked between the Log()
call and the actual processing. This path is described in the diagram below and it's essential for identifying logging extension points.
flowchart TD depsProvider[depsProvider : **ImADependencyProvider**] --> |GetLogger|LoggerFactory[LoggerFactory : **ImALoggerFactory**] LoggerFactory --> |Get new InMemoryLogger from depsProvider|InMemoryLogger InMemoryLogger[InMemoryLogger : LoggerBase : **ImALogger**] --> |**Log**|internalLogDictionary[**Store LogEntry in memory**] InMemoryLogger[InMemoryLogger : LoggerBase : **ImALogger**] --> |Process Log Entries|InMemoryLogProcessorRegistry[LogProcessorRegistry : **ImALogProcessorRegistry**] InMemoryLogProcessorRegistry --> |For each IoC registered log processor|LogProcessor[LogProcessor : LogProcessorBase : **ImALogProcessor**] LogProcessor --> |For each log entry|IsEligible{Is Eligible} IsEligible --> |No|StopNotEligible[[🛑]] IsEligible --> |Yes|Process[✅**Process Log Entry**] Process --> |ConsoleLogProcessor : **ImALogProcessor**|LogToConsole[Log to **console**] Process --> |FileSystemLogProcessor : **ImALogProcessor**|LogToFiles[Log to **files**] Process --> |DbLogProcessor : **ImALogProcessor**|LogToExceptionless[Log to **database**] Process --> |CustomLogProcessor : **ImALogProcessor**|LogToCustom[Log to **_your custom implementation_**]
Out of the box
H.Necessaire suite comes with various out-of-the-box ImALogProcessor
implementations.
H.Necessaire Core
- ConsoleLogProcessor - outputs the logs into console. This is the single default logging when you're using just the core nuget.
H.Necessaire.Runtime
- PersistentLogProcessor - saves the logs in the persistent storage registered as
ImAStorageService<Guid, LogEntry>
, which defaults to the File System.- When a dedicated runtime nuget is being used (e.g.: SQL, RavenDB, Azure CosmosDB, Google FirestoreDB, etc.), the file system storage is replaced by the underlying runtime storage.
- Or, if a custom implementation of
ImAStorageService<Guid, LogEntry>
is registered, then that's what it'll be used.
Dedicated Log Services
There are dedicated logging services available, such as Azure AppInsights, Exceptionless, NewRelic, etc.
H.Necessaire offers out-of-the-box integrations with Exceptionless and NewRelic via explicit NuGets.
Exceptionless
dotnet add package H.Necessaire.Exceptionless
ImADependencyProvider depsProvider
= H.Necessaire.IoC
.NewDependencyRegistry()
.Register<HNecessaireDependencyGroup>(() => new HNecessaireDependencyGroup())
.Register<H.Necessaire.Exceptionless.ExceptionlessDependencyGroup>(() => new H.Necessaire.Exceptionless.ExceptionlessDependencyGroup())
;
NewRelic
dotnet add package H.Necessaire.Logging.NewRelic
ImADependencyProvider depsProvider
= H.Necessaire.IoC
.NewDependencyRegistry()
.Register<HNecessaireDependencyGroup>(() => new HNecessaireDependencyGroup())
.Register<H.Necessaire.Logging.NewRelic.NewRelicLoggingDependencyGroup>(() => new H.Necessaire.Logging.NewRelic.NewRelicLoggingDependencyGroup())
;
Extending H.Necessaire Logging
If you've read this far, you probably figured it out that the logging mechanism is very easy to extend.
You simply need to implement a concrete ImALogProcessor
and register it in the DI container at app start.
Example:
internal class MyCustomLogProcessor : ImALogProcessor
{
public ImALogProcessor ConfigWith(LogConfig logConfig) => this;
public LoggerPriority GetPriority() => LoggerPriority.Immediate;
public Task<bool> IsEligibleFor(LogEntry logEntry) => true.AsTask();
public Task<OperationResult<LogEntry>> Process(LogEntry logEntry)
{
Console.WriteLine("~~~CustomLogProcessor BEGIN~~~");
Console.WriteLine(logEntry.Message);
Console.WriteLine("~~~CustomLogProcessor END~~~");
return OperationResult.Win().WithPayload(logEntry).AsTask();
}
}
[...]
ImADependencyProvider depsProvider
= H.Necessaire.IoC
.NewDependencyRegistry()
.Register<HNecessaireDependencyGroup>(() => new HNecessaireDependencyGroup())
.Register<MyCustomLogProcessor>(() => new MyCustomLogProcessor())
;